Overview

Give your agent a project boundary it actually respects

Each page here explains one capability. Complex-task goals and orchestration live in Agent & Tasks.

Workspace: your project's security boundary#

Workspace is kxen's registration record for a local project, and the security boundary for every project-level capability.

Where you find it#

The left sidebar shows your registered Workspaces. Add a project through the system's native directory picker, and create, switch, and organize Sessions underneath a Workspace.

What a Workspace decides#

  • A Session's default working directory.
  • The lookup root for project configuration and project knowledge.
  • The project lifecycle for MCP, LSP, and Hooks.
  • The default scope file tools are allowed to access.
  • The repository context for Checkpoint and Worktree.
  • Git status, the change view, and project-level diagnostics.

Trust state#

Workspace trust controls whether a project's configuration, MCP, Skill, Command, and knowledge get injected. An untrusted project's content can still be indexed, but it never enters the model prompt or an executable tool surface directly.

Your own personal-scope configuration and knowledge follow you, regardless of a project's trust state.

Usage boundary#

A Workspace isn't just an arbitrary directory string. When you switch Workspaces, every service depending on the working directory has to use the new project context. Don't use your home root as an ordinary Workspace, and don't mix multiple unrelated repositories into one Workspace.

Workspaces board: watch every project at once#

The Workspaces board lets you observe execution state across multiple projects. It's not a new execution engine — it's a cross-Workspace status rollup.

Where you find it#

Open Workspaces from the left sidebar. The board shows current Sessions and project status per Workspace, surfacing items that need your attention first.

What it shows#

  • Running Sessions.
  • Bound Goals and their status.
  • Kanban boards and pending-review counts (see the Kanban pipeline for board mechanics).
  • Worktree count and branch information.
  • Waiting-message and scheduled-task counts.
  • Dirty-file counts across working trees.

Goal status distinguishes in-progress, blocked, budget-limited, and paused. The board reads from the backend's own running truth — it never treats "the frontend is still streaming" as task status.

How to use it#

Use the board to find projects that are still running, waiting, or holding uncommitted changes. Select a card to jump back to that Session and keep working — the actual actions still happen on the Session, Goal, Schedule, or Worktree page itself.

Session: your persistent, recoverable work unit#

Session is the basic unit of you and an agent working together. It binds to one working directory, and keeps the full timeline from your messages to tool execution results.

Where you find it#

Every Workspace has its own Session list. Create, switch, rename, pin, sort, and delete Sessions freely.

What it saves#

  • Title, working directory, and current model.
  • User and assistant messages.
  • Tool calls, tool results, and Approval outcomes.
  • Reasoning, images, and hidden context.
  • Associations to a parent Session, Goal, Team, Schedule, and recovery points.

Session messages append-only. Model input, append, fork, rewind, compaction, export, and knowledge consolidation all read strictly — a bad JSONL line fails closed rather than continuing to write on top of corrupted history. A diagnostic view can still keep already-parsed messages, but explicitly flags any bad line. Metadata's message_revision only advances monotonically on a real append or rewrite, letting kxen tell apart changes within the same millisecond; a perfectly idempotent append never advances the revision.

The waiting queue assigns every message a stable ID and creation time. Claim, append, and acknowledge persist in separate steps, so a crash replay never duplicates the same user message, and never re-parses an already-committed file, URL, context, or image snapshot.

Deletion and recovery#

Deleting a Session uses a persistent tombstone to block new runs, queue admission, and new Knowledge writes, and cancels any active run — waiting up to 3 seconds — then waits for that Session's consolidation lease to release. If you chose to delete-and-consolidate, a distillation, usage-settlement, or revision-validation failure stops the deletion.

Before actual cleanup, kxen builds a recovery bundle covering metadata, messages, compaction, queue, artifacts, Team, Goal, Schedule, and usage associations. Only once the bundle stages successfully does it purge the original data, then move the bundle into the system trash. A mid-way failure either rolls back precisely or keeps the tombstone for startup recovery — it never reports a partial deletion as success.

Restoring a .kxen-session bundle from the system trash lets the app's startup scan re-import it. A target-path conflict or a corrupted bundle fails closed and preserves the recovery evidence.

Storage-consistency recovery#

When the message JSONL or the pending queue is blocked, has an incomplete tail, or is corrupted, a storage-recovery panel appears above Composer. A healthy Session never shows this panel.

  • The check separately reports integrity, write-blocking, and provable recoverability for the message log and the queue.
  • A complete JSON record missing only its trailing newline keeps its record and simply gets the newline appended. An incomplete final segment is only ever moved out of the working copy when it's provably the tail.
  • Before repairing JSONL, kxen fully backs up the original bytes to sessions/.recovery/, permission 0600, and shows you the evidence path in the UI.
  • Mid-file corruption, a duplicate message ID, a mismatched Session ID, or a queue that can't align with its expected snapshot never auto-repairs. The original file stays untouched, and you should export a diagnostic bundle first.
  • Recovery never runs during an active run. The backend only clears the write block once both the Session and Queue stores are provably recoverable.

Timeline actions#

You can edit and resend a message, fork a new Session from a specific message, re-run an assistant turn, and export the current Session. A fork keeps the original Session intact — it never mixes two subsequent executions into the same timeline.

State boundary#

Every run has to end completed, canceled, or errored. The UI no longer streaming updates doesn't mean the backend run has actually ended. Active state, the waiting queue, and Approval together decide whether a Session is still running.

Entering a Session or manually retrying reconciles the request-start baseline, the backend snapshot, and any live events received while loading, matched by message ID and Approval occurrence. Already-persisted records take over their matching optimistic or live-prefix entries, but a record that only exists in the live stream is never erased by a stale snapshot. Switching Sessions, a storage recovery, or a new queue update invalidates the old load generation — a late result can never resurrect the previous Session's timeline or queue.

The timeline and the queue each keep their own error source, and can be retried independently. Once storage recovery succeeds, the UI cancels the old generation, clears the old load error, and re-reads both from the backend's own truth.

Composer: your unified input surface#

Composer is a Session's unified input surface. It turns natural language, context, and explicit controls into a single agent request.

What it accepts#

  • Plain text.
  • File and directory references.
  • Image attachments.
  • Large pasted content.
  • Slash Commands and Skills.
  • A Knowledge write target.
  • Voice transcription.

Quick triggers#

  • @ searches for and references a file or directory inside the Workspace.
  • / only triggers Command and invocable Skills at the start of a line.
  • # chooses a project or personal knowledge write target.
  • Hold spacebar to enter voice input.

Enter never misfires while your IME is composing. Every Session keeps its own Composer draft, so switching back restores your unsent text.

Proactive context suggestions#

Plain text input doesn't need an @, /, or # trigger. The default local suggestion reads your full draft, blending in recent Session text, current attachments, prior context, recently involved files, Git changes, and recently touched files. The trigger popup always takes priority; suggestions never show while your cursor isn't at the end of the text, while your IME is composing, while recording, or while the Session is running.

A candidate's source is tagged Local, Embedding, or LLM. A file candidate only ever becomes a row chip; a text candidate only ever gets inserted into Composer — neither one sends automatically. ArrowUp/ArrowDown selects, Tab accepts, Escape dismisses the current draft's suggestions; Enter always keeps its send meaning.

Embedding and LLM suggestions are off by default, and need an explicit data-boundary confirmation in Settings' advanced section before you can turn them on. A network failure, an unavailable model, or invalid remote output keeps the local result and never blocks your input.

Before you send#

Composer shows the current model and a token estimate. Attachments resolve into context or an image payload at send time. Files still stay bound by the Workspace boundary and Safety — adding something to Composer never gives the agent access beyond that boundary.

Sending while a run is active#

The default behavior adds a new message to the waiting queue. You can also configure it in Settings to interrupt the current run first. See exact state transitions in the message queue.

Context: control what the agent sees in one request#

Context is information you explicitly add to a request — it's never the entirety of your Workspace's content.

How to add it#

  • Type @ in Composer to search for a file or directory.
  • Use the attachment menu to select a file.
  • Drag a file or image into Composer.
  • Paste an image or a large block of text directly.

Files, directories, and images show as removable chips. Large pasted text collapses and saves, restoring its full content at send time, so the input box never gets swamped by long text.

When it resolves#

Attachments resolve at send time. If a file changes after you added its chip, what actually gets sent reflects its state at resolution time. An external file always needs native file-picker authorization; a file inside the Workspace still passes a path-boundary check.

Compared to automatic context#

Explicit context is entirely under your control. The agent can still read related files through its own tools when permissions allow. Rules, Notes, and Memory get injected by the knowledge system based on scope and retrieval results — they're never Composer attachments.

Keeping it small#

Prefer referencing the smallest file set the task actually needs. A directory reference lets the agent discover content on its own, but it also widens the later read scope. The token estimate is meant to hint at input size — it's never the model's final billed value.

Message queue: control what happens while an agent is running#

The message queue solves the problem of sending another message into the same Session before the agent has finished.

stateDiagram-v2
  state "Current run" as Running
  state "Waiting queue" as Queued
  state "Canceling current run" as Cancelling
  state "Canceled" as Cancelled
  [*] --> Running
  Running --> Queued: queue
  Queued --> Running: current run completes
  Running --> Cancelling: interrupt
  Cancelling --> Running: start new run
  Running --> Cancelled: stop
  Cancelled --> [*]

Queue mode#

queue is the default. A new message joins the current Session's waiting queue, and continues in order once the current run finishes. It fits adding follow-up work without interrupting a tool call already in progress.

Queue state persists as queued and in_flight. Every delivery has a stable ID and its original creation time; the backend claims and persists it first, then idempotently appends the Session user message using that same ID and time, only acknowledging after persistence succeeds. If the app exits abnormally after a claim, an in_flight delivery gets replayed; if the crash happened between the JSONL append and the acknowledgment, the replay recognizes the same message ID — it never duplicates the append, and never silently loses it.

File, URL, Note, and image references resolve only on first delivery. Once a user message is written to the Session, a replay uses exactly the text, context, and image snapshot already committed to JSONL — it never re-reads the current file, re-fetches a URL, or generates a new timestamp. If a stable ID already exists but its role or content shape is invalid, that delivery moves to blocked, instead of continuing to execute on drifted input. Whether the subsequent model execution finishes doesn't change the fact that the user message is already persisted.

Assistant messages and terminal states persist first, and only then does the queue continue. When there's a next delivery, the backend executes the queue claim and the old-token-to-new-token handover inside the same active-run critical section, with no exposed window a second run could preempt. So the authoritative running state stays true between a terminal state and continuing — the UI's streaming indicator and stop button reconcile against a Session snapshot, never inferring from the last terminal event alone.

The frontend advances a loading generation for every local send, cancel, and live event on the queue. An earlier queue snapshot, even arriving late, can never overwrite these newer updates — the UI then re-reads the authoritative queue fresh from the backend. Timeline loading failures and queue loading failures are shown separately; retrying one never clears the other's error.

If the queue file gets corrupted, kxen keeps the original file and blocks further queue operations for that Session, instead of interpreting the damage as an empty queue. If a rename is already visible but the parent-directory fsync fails, the current process keeps the exact expected snapshot and fails closed. The storage-recovery panel above Composer only re-fsyncs and clears the block once the on-disk state exactly matches that snapshot — when it can't prove consistency, it keeps the original file and asks you to export a diagnostic bundle and check manually first.

Interrupt mode#

interrupt cancels the current run first, then processes the new message. It fits correcting direction immediately, but any result the current turn hasn't finished yet won't continue.

You'll find the setting in Settings' general area. Changes apply to messages sent from then on.

Stopping#

Composer's Stop action directly cancels the current run, taking priority over an Approval wait or a long command still running. Cancellation always has to produce an explicit terminal state — the waiting queue never resumes an already-canceled tool call in the background.

Stopping or interrupting ends the current tool's future. MCP removes the pending request and best-effort notifies the server of the cancellation; exec terminates the matching process and cleans up. Cancellation isn't a transactional rollback of an external side effect — a write a tool already completed before receiving the cancellation can still exist.

Usage boundary#

The queue only guarantees message order within the same Session. Different Sessions, Subagents, Workflow agents, and Team members are each coordinated by their own running state and MRM resource limits.

Updated

Was this page helpful?