Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/keybindings.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,11 @@ On Windows Terminal, `Ctrl+V` may be handled by the terminal paste command befor
Terminals that implement OSC 5522 enhanced paste can send clipboard MIME data directly to `omp`; image pastes are attached as `[Image #N]`, while text/plain paste events keep normal paste behavior. When OSC 5522 is unavailable, bracketed paste still handles text, and a pasted single image-file path is loaded as an image when the file is readable from the `omp` host.

Older unqualified action names are migrated when `keybindings.yml` is loaded, but new docs and new configs should use the namespaced action IDs above. Existing `keybindings.json` files are still accepted and migrated to `keybindings.yml`; `keybindings.yaml` is also accepted.

## Built-in editor chords

| Key | Action |
| --- | ------ |
| `Enter` | Send message |
| `Shift+Enter` / `Alt+Enter` / `Ctrl+J` | Insert a newline |

7 changes: 6 additions & 1 deletion docs/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ A value of `-1` means "use the provider/model default" — `omp` does not send t
| `presencePenalty` | number | `-1` | Presence penalty. |
| `repetitionPenalty` | number | `-1` | Repetition penalty. |
| `serviceTier` | enum | `none` | `none`, `auto`, `default`, `flex`, `scale`, `priority`, `openai-only`, `claude-only`. |
| `fastModeScope` | enum | `both` | Which provider families `/fast on` and the fast-mode toggle affect: `both`, `openai`, or `claude`. |
| `personality` | enum | `default` | `default`, `friendly`, `pragmatic`, `none`. |

### Retry and fallback
Expand Down Expand Up @@ -388,6 +389,8 @@ tools:
| `tools.approval` | record | `{}` | Per-tool policy keyed by tool name; each value is `allow`, `deny`, or `prompt`. e.g. `omp config set tools.approval '{"bash":"prompt"}'`. |
| `tools.discoveryMode` | enum | `auto` | `auto`, `off`, `mcp-only`, `all`. Controls dynamic tool discovery. |
| `tools.essentialOverride` | array | `[]` | Tool names kept available even when tools are narrowed. |
| `task.eager` | enum | `default` | `default`, `preferred`, `always`; controls how strongly the agent is pushed toward subagent delegation. |
| `todo.eager` | enum | `default` | `default`, `preferred`, `always`; controls first-turn todo-list creation guidance. |
| `tools.maxTimeout` | number | `0` | Max tool runtime in seconds; `0` = no cap. |
| `tools.intentTracing` | boolean | `true` | Record per-call intent strings. |
| `tools.outputMaxColumns` | number | `768` | Per-line byte cap for streaming output; `0` disables. |
Expand Down Expand Up @@ -608,7 +611,9 @@ searxng:
| `exa.enableResearcher` | boolean | `false` | Exa researcher. |
| `exa.enableWebsets` | boolean | `false` | Exa websets. |
| `searxng.endpoint` | string | _(unset)_ | SearXNG instance URL. |
| `searxng.token` | string | _(unset)_ | SearXNG token; also `searxng.basicUsername`/`searxng.basicPassword`/`searxng.categories`/`searxng.language`. |
| `searxng.categories` | string | _(unset)_ | Optional categories passed to SearXNG when an endpoint is configured. |
| `searxng.language` | string | _(unset)_ | Optional language code passed to SearXNG when an endpoint is configured. |
| `searxng.token` | string | _(unset)_ | SearXNG token; also supports `searxng.basicUsername`/`searxng.basicPassword`. |
| `auth.broker.url` | string | _(unset)_ | Auth-broker URL. Overridden by `OMP_AUTH_BROKER_URL`. |
| `auth.broker.token` | string | _(unset)_ | Auth-broker token. Overridden by `OMP_AUTH_BROKER_TOKEN`. |

Expand Down
8 changes: 4 additions & 4 deletions docs/tools/irc.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,16 @@
## Outputs
- Single-shot `AgentToolResult`; no streaming updates.
- `content` is one text block:
- `list`: `No other agents.` or `<n> peer(s):` bullets — `id [displayName · kind · status]` plus unread count, parent, and last-activity age; a footer notes that parked agents are revived automatically when messaged.
- `list`: `No other agents.` or `<n> peer(s):` bullets — `id [displayName · kind · status]` plus current `activity` when a running peer reports work, unread count, parent, and last-activity age; a footer notes that parked agents are revived automatically when messaged.
- `send`: per-recipient delivery receipts (`injected` / `woken` / `revived` / `failed — <error>`); with `await: true`, the reply body or a clean no-reply timeout note.
- `wait`: the consumed message as `[<msgId>] <from>: <body>` (with a reply-to tag), or `No message within <duration>.`
- `inbox`: `Inbox empty.` or `<n> message(s):` bullets.
- `details: IrcDetails`: `{ op, from?, to?, receipts?, waited?, inbox?, peers? }`. `waited` is `null` when a wait timed out; `receipts` carry `{ to, outcome, error? }`.
- `details: IrcDetails`: `{ op, from?, to?, receipts?, waited?, inbox?, peers? }`. `peers[]` entries carry `activity?`, `unread`, `parentId?`, and `lastActivity`; `activity` is a display-only gist of the peer's current work and is cleared when the peer stops running. `waited` is `null` when a wait timed out; `receipts` carry `{ to, outcome, error? }`.

## Flow
1. `IrcTool.createIf` constructs the tool only when `isIrcEnabled` passes and the session has both an `AgentRegistry` and `getAgentId`. There is no `irc.enabled` setting: availability is derived — true for every subagent (`taskDepth > 0`; a parent always exists) and for any session that can still spawn subagents through the task tool. Only a top-level session with task spawning unavailable has no peers, hence no irc.
2. `execute` resolves the registry and sender id; missing either returns a text error result instead of throwing.
3. `op: "list"`: `registry.list()` minus self and minus `aborted` agents — `parked` peers ARE listed. Each row includes the unread count from `IrcBus.unreadCount(...)` and last activity.
3. `op: "list"`: `registry.list()` minus self and minus `aborted` agents — `parked` peers ARE listed. Each row includes `activity` for running peers, unread count from `IrcBus.unreadCount(...)`, and last activity.
4. `op: "send"` validates `to`/`message`, rejects self-sends, and rejects `await` with `to: "all"`.
5. Target resolution: broadcasts fan out to `registry.listVisibleTo(senderId)` (live peers only — `running`/`idle`; reviving every parked agent on a broadcast would be a stampede). Direct sends go through the bus unfiltered, so a parked recipient is revived.
6. `IrcBus.send(...)` is fire-and-forget — it never blocks on the recipient generating anything. Delivery by recipient status:
Expand All @@ -54,7 +54,7 @@
10. Timeouts resolve as `params.timeoutMs ?? irc.timeoutMs`, normalized: `0` disables the timeout, negative/non-finite values fall back to the default `120_000`, positive values are truncated and clamped to ≥ 1 ms.

## Modes / Variants
- `list`: enumerate peers with status (`running`/`idle`/`parked`), unread counts, and last activity.
- `list`: enumerate peers with status (`running`/`idle`/`parked`), current activity gist for running peers, unread counts, and last activity.
- `send` direct: one exact peer id; wakes idle peers, revives parked ones.
- `send` broadcast: `to: "all"` to every live peer; parked peers are skipped.
- `send` + `await: true`: round-trip convenience — send, then wait for the next message from that peer. Marks the send `expectsReply`, enabling the busy-recipient auto-reply path when async execution is disabled.
Expand Down
43 changes: 43 additions & 0 deletions docs/tools/learn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# learn

> Capture a reusable lesson to long-term memory, optionally creating or updating a managed skill in the same call.

## Source
- Entry: `packages/coding-agent/src/tools/learn.ts`
- Model-facing prompt: `packages/coding-agent/src/prompts/tools/learn.md`
- Key collaborators:
- `packages/coding-agent/src/autolearn/managed-skills.ts` — managed skill path/name validation and `SKILL.md` writes.
- `packages/coding-agent/src/memory-backend/local-backend.ts` — local file-backed lesson storage.
- `packages/coding-agent/src/hindsight/state.ts` and `packages/coding-agent/src/mnemopi/state.ts` — remote/local memory retention.

## Inputs

| Field | Type | Required | Description |
|---|---|---:|---|
| `memory` | `string` | Yes | Durable, self-contained lesson. Include what, when, and why. |
| `context` | `string` | No | Source context for the lesson. |
| `skill` | `{ action, name, description, body }` | No | Also create or update a managed skill. `action` is `create` or `update`; `name` is kebab-case; `body` is Markdown without frontmatter. |

## Outputs
- Memory only: `Lesson stored.` or `Lesson queued for retention.` with `details.skill = null`.
- Memory plus skill: `<lesson result>. Created/Updated managed skill "<name>".` with `details.skill = <name>`.
- Authored-skill name collision on `create`: error text explains that managed skills cannot override authored skills; the memory lesson was already stored or queued.

## Flow
1. `LearnTool.createIf(...)` exposes the tool only when `autolearn.enabled=true` and `memory.backend` is `hindsight`, `mnemopi`, or `local`.
2. `execute(...)` stores the lesson through the active backend:
- `mnemopi` writes a fact with source `coding-agent-learn` and fails if no memory id is returned;
- `local` appends through the local backend and fails when sanitization leaves nothing to store;
- `hindsight` queues the lesson for asynchronous retention.
3. If `skill` is present, the tool validates the managed skill name, refuses authored-skill shadowing on `create`, then writes the managed skill under `~/.omp/agent/managed-skills`.

## Limits & Caps
- Availability requires both `autolearn.enabled` and an active memory backend.
- The skill side never edits user-authored skills; authored skills keep precedence.
- `skill.body` must omit frontmatter; frontmatter is generated from `name` and `description`.

## Errors
- `Mnemopi backend is not initialised for this session.`
- `Hindsight backend is not initialised for this session.`
- `Lesson was empty after sanitization; nothing stored.`
- Managed skill write failures surface after the memory outcome, because the lesson may already be stored or queued.
40 changes: 40 additions & 0 deletions docs/tools/manage-skill.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# manage_skill

> Create, update, or delete isolated managed skills used by the auto-learn workflow.

## Source
- Entry: `packages/coding-agent/src/tools/manage-skill.ts`
- Model-facing prompt: `packages/coding-agent/src/prompts/tools/manage-skill.md`
- Key collaborators:
- `packages/coding-agent/src/autolearn/managed-skills.ts` — managed skill directory, name validation, create/update/delete primitives.
- `packages/coding-agent/src/extensibility/skills.ts` — authored-skill collision checks.

## Inputs

| Field | Type | Required | Description |
|---|---|---:|---|
| `action` | `"create" | "update" | "delete"` | Yes | Operation to perform. |
| `name` | `string` | Yes | Kebab-case skill name. |
| `description` | `string` | Create/update | One-line description of when to use the skill. |
| `body` | `string` | Create/update | `SKILL.md` body in Markdown, without frontmatter. |

## Outputs
- Delete: `Deleted managed skill "<name>".` with `{ action: "delete", name }`.
- Create/update: `Created/Updated managed skill "<name>" (managed-skills/<path>).` with `{ action, name }`.
- Authored-skill name collision on `create`: error text explains that managed skills cannot override authored skills and asks for a different name.

## Flow
1. `ManageSkillTool.createIf(...)` exposes the tool only when `autolearn.enabled=true`.
2. Validation requires `description` and `body` for `create` and `update`; `delete` needs only `name`.
3. `create` refuses names already claimed by authored skills, because managed skills resolve below authored skills and would never surface.
4. Writes target `~/.omp/agent/managed-skills`; managed skills are surfaced like normal skills in future sessions.

## Limits & Caps
- This is a write-tier tool.
- Managed skills are separate from user-authored skills.
- `body` must omit frontmatter; it is generated from `name` and `description`.

## Errors
- Validation rejects create/update without both `description` and `body`.
- Create fails when the managed skill already exists or an authored skill owns the name.
- Update/delete fail when the managed skill does not exist.
5 changes: 3 additions & 2 deletions docs/tools/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@

## Inputs

The wire schema is shape-swapped by `task.batch` (default on). One unit of work is the task item `{ id?, description?, assignment, isolated? }` (`isolated` only when `task.isolation.mode` is not `none`):
The wire schema is shape-swapped by `task.batch` (default on). One unit of work is the task item `{ id?, description?, role?, assignment, isolated? }` (`isolated` only when `task.isolation.mode` is not `none`):

- **Batch shape** (`task.batch` on): `{ agent, context, tasks: item[] }` — one subagent per item, all run under the same fan-out rules. `context` is **required** shared background rendered into every spawned subagent's system prompt (`CONTEXT` section); `isolated` is per item.
- **Batch shape** (`task.batch` on): `{ agent, context, tasks: item[] }` — one subagent per item, all run under the same fan-out rules. `context` is **required** shared background rendered into every spawned subagent's system prompt (`CONTEXT` section); `role` and `isolated` are per item.
- **Flat shape** (`task.batch` off): `{ agent, ...item }` — exactly one spawn per call. Shared background goes into a `local://` file (e.g. `local://ctx.md`) that each assignment references; subagents share the parent's `local://` root.

| Field | Type | Required | Description |
Expand All @@ -37,6 +37,7 @@ The wire schema is shape-swapped by `task.batch` (default on). One unit of work
| `context` | `string` | Yes (batch) | Shared background prepended to every spawn of the call via the subagent system prompt. Rejected when `task.batch` is off. |
| `tasks` | `array` | Yes (batch) | One task item per subagent. Provided ids must be unique within the call (case-insensitive). Rejected when `task.batch` is off. |
| `id` | `string` | No | Stable agent id, schema max length 48. Defaults to a generated AdjectiveNoun name. Uniquified per session by `AgentOutputManager`. Item field in batch shape, top-level in flat shape. |
| `role` | `string` | No | Specialist role/expertise for this spawn, schema max length 256. Shapes the subagent system-prompt identity and roster display name; generic `task` / `quick_task` spawns without roles get an advisory nudge. Item field in batch shape, top-level in flat shape. |
| `description` | `string` | No | UI label only; the subagent never sees it. Item field in batch shape, top-level in flat shape. |
| `assignment` | `string` | Yes | The work — complete, self-contained instructions. Empty-after-trim is rejected. Item field in batch shape, top-level in flat shape. |
| `isolated` | `boolean` | No | Run in an isolated workspace and return patches. Exists only when `task.isolation.mode` is not `none`; per item in batch shape, top-level in flat shape. Isolated agents are torn down at completion — not revivable. |
Expand Down
Loading