@chorded/chord 0.54.0 → 0.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +141 -554
  2. package/package.json +19 -5
package/README.md CHANGED
@@ -1,591 +1,178 @@
1
- # chord
1
+ <h1 align="center">chord</h1>
2
+
3
+ <p align="center">
4
+ <strong>One terminal for every coding agent.</strong><br>
5
+ Claude Code, Codex, Gemini CLI, Cursor, OpenCode and 30 more, in one
6
+ keyboard-driven window, side by side, working as a team.
7
+ </p>
8
+
9
+ <p align="center">
10
+ <a href="https://www.npmjs.com/package/@chorded/chord"><img alt="npm" src="https://img.shields.io/npm/v/@chorded/chord?color=47e7a5&label=npm"></a>
11
+ <a href="https://github.com/IKatsuba/chord/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/IKatsuba/chord/actions/workflows/ci.yml/badge.svg"></a>
12
+ <a href="LICENSE"><img alt="MIT licence" src="https://img.shields.io/badge/licence-MIT-blue"></a>
13
+ <img alt="macOS and Linux" src="https://img.shields.io/badge/platform-macOS%20%7C%20Linux-lightgrey">
14
+ </p>
15
+
16
+ <p align="center">
17
+ <img src="docs/images/team.png" alt="chord handing an issue to a team: a lead, a tester on Claude and a coder on Codex, each with its state in the list under the prompt" width="900">
18
+ </p>
19
+
20
+ chord brings Claude Code, Codex, Gemini CLI and other coding agents into one
21
+ terminal interface: the same transcript, diffs, permission prompts, slash
22
+ commands, `@` mentions and plans. It connects to agents through the
23
+ [Agent Client Protocol](https://agentclientprotocol.com).
24
+
25
+ Run agents side by side or give a task to a team. For example, have Codex
26
+ write a fix and Claude review it, each with its own model and role. Agents
27
+ exchange messages, permission requests come to you, and a saved team can
28
+ take on your next task.
2
29
 
3
- A full-screen terminal client for coding agents that speak the
4
- [Agent Client Protocol](https://agentclientprotocol.com) — Claude Code, Codex,
5
- Gemini CLI, Cursor, fx, OpenCode and the rest — with everything people reach for
6
- in Claude Code's own interface: permission modes, slash commands, `@` file
7
- mentions, `!` bash mode, plans, diffs, history, resume, and a keyboard for all
8
- of it.
30
+ ```sh
31
+ npm install -g @chorded/chord
32
+ chord # Claude Code, here
33
+ chord codex # or any other agent
34
+ ```
9
35
 
10
- > **Status: pre-alpha.** You can send prompts, read the replies as plain
11
- > text, and answer the agent's permission requests and forms; tool calls and
12
- > the rest are on their way.
13
- > `docs/FEATURES.md` is the map of what is coming and in which order.
36
+ ## Why chord
14
37
 
15
- ## Why
38
+ - **Any agent, one interface.** 35 agents out of the box, from the
39
+ [ACP Registry](https://agentclientprotocol.com) and their own CLIs. Switch
40
+ agents without relearning keys.
41
+ - **Agents that work together.** Open a second agent beside the one you talk
42
+ to, hand a job to a saved team, and watch each of them in a list under the
43
+ prompt. Messages go between them; permissions still come to you.
44
+ - **Every action has a key.** Nothing on screen needs a mouse. `?` lists them
45
+ all, and a keybindings file moves them.
46
+ - **Nothing to set up.** One binary, no account, no daemon. chord starts the
47
+ agent, keeps the session, and gives it back with `chord --continue`.
48
+ - **Open source.** MIT, built on [OpenTUI](https://github.com/anomalyco/opentui)
49
+ and the [ACP SDK](https://github.com/agentclientprotocol/typescript-sdk).
16
50
 
17
- Claude Code's terminal interface is the best one there is for working with a
18
- coding agent, and it only talks to Claude. ACP separates the agent from the
19
- interface, so the interface can be one program and the agent anything. chord is
20
- that program: open source, one binary, one window, any agent.
51
+ ## A tour
21
52
 
22
- chord is the open sibling of [Chorded](https://chorded.app), a native macOS
23
- workspace for agent sessions driven by key chords. The two share a belief —
24
- every action has a key, and nothing needs a pointer — and a mark, which chord
25
- draws when a session starts. They share no code, no licence and no account.
53
+ ### Diffs you can read
54
+
55
+ Edits arrive as numbered, highlighted diffs, folded until you want the whole
56
+ thing (`ctrl+o`).
57
+
58
+ <img src="docs/images/edit.png" alt="An Edit tool call drawn as a coloured diff" width="900">
59
+
60
+ ### You stay in charge
61
+
62
+ Each permission the agent asks for is a choice under the transcript, answered
63
+ with a number or the arrows. `shift+tab` cycles the agent's permission modes.
64
+
65
+ <img src="docs/images/permission.png" alt="The permission prompt: Allow, Always allow, Deny" width="900">
66
+
67
+ ### Many agents in one window
68
+
69
+ Up to nine sessions as tabs, each with its own agent, transcript and draft.
70
+ A tab in the background marks what it waits for, and `ctrl+x a` takes you
71
+ there.
72
+
73
+ <img src="docs/images/tabs.png" alt="Two tabs, claude waiting on a permission behind, codex in front" width="900">
74
+
75
+ ### Subagents, folded
76
+
77
+ When the agent fans out, its subagents run as one tree with their latest call
78
+ each, and their full work is a key away.
79
+
80
+ <img src="docs/images/subagents.png" alt="Two subagents running in parallel under one block" width="900">
81
+
82
+ ### Teams
83
+
84
+ Describe how you work and the agent proposes a team: a lead and its members,
85
+ each on the runtime, model and mode you want. Save it once, then hand it any
86
+ job with `/team run bugfix <job>`.
87
+
88
+ <img src="docs/images/proposal.png" alt="A proposed team as a table of agents, with a box asking where to save it" width="900">
89
+
90
+ ### Pick up where you left off
91
+
92
+ `/resume` lists this directory's earlier sessions and saved windows; quit a
93
+ window of several tabs and chord prints the one command that brings them all
94
+ back.
95
+
96
+ <img src="docs/images/resume.png" alt="The resume picker listing earlier sessions" width="900">
26
97
 
27
98
  ## Install
28
99
 
29
100
  ```sh
30
- npm install -g @chorded/chord
101
+ npm install -g @chorded/chord # or bun, pnpm, yarn
31
102
  ```
32
103
 
33
- The npm package is a small shim around a prebuilt standalone binary for your
34
- platform (macOS and Linux; arm64 and x64). There is no Node build of chord.
35
- The macOS binaries are signed and notarised.
104
+ The package is a small shim around a prebuilt binary for macOS and Linux,
105
+ arm64 and x64; the macOS binaries are signed and notarised. `chord upgrade`
106
+ updates it through the package manager that installed it.
36
107
 
37
- `chord upgrade` installs the latest version through the package manager
38
- that installed chord (npm, bun, pnpm or yarn); `chord upgrade --version
39
- <version>` installs that one, and `chord upgrade -l` lists them.
108
+ chord starts each agent for you (through `npx` or `uvx`, or the agent's own
109
+ CLI where it has one), so the agent's own login is all it needs: sign in to
110
+ Claude Code, Codex or Gemini as you normally would.
40
111
 
41
- Or build from source with [Bun](https://bun.sh) 1.4.2 or newer:
112
+ To build from source, with [Bun](https://bun.sh) 1.4.2 or newer:
42
113
 
43
114
  ```sh
115
+ git clone https://github.com/IKatsuba/chord && cd chord
44
116
  bun install
45
- bun run compile --install # compiles into ~/.local/bin/chord
117
+ bun run compile --install # into ~/.local/bin/chord
46
118
  ```
47
119
 
48
120
  ## Use
49
121
 
50
122
  ```sh
51
- chord # Claude Code, or your settings' agent, here
52
- chord codex # any agent `chord agents` lists
123
+ chord # your default agent in this directory
53
124
  chord gemini -C ~/src/app
54
- chord --continue # Claude Code's latest session in this directory, again
55
- chord --resume <id> # a session by its id, which chord prints when you quit
56
- chord -r <id> -r <id> … # each a tab of one window, the first in front
57
- chord --resume w-<id> # a whole window again, as chord prints when you quit it
58
- chord --resume # pick an earlier session or a saved window first
59
- chord agents # the agents chord can start: name, what starts each, and whether PATH has its CLI
60
- chord -p "Explain src/main.tsx" # the reply on stdout, then exit
125
+ chord agents # every agent chord can start, and whether it is installed
126
+ chord --continue # the latest session here, again
127
+ chord --resume # pick an earlier session or window
128
+ chord -p "Explain src/main.tsx" # one reply on stdout, for scripts
61
129
  git diff | chord -p "Review this" --output-format json
62
130
  ```
63
131
 
64
- Inside chord, `/resume` lists this directory's earlier sessions and saved
65
- windows in one list, newest first, each with when it was last used and its
66
- first prompt, after its name for an agent another agent started; a window reads `▣ 3 sessions · claude, codex, claude` and its
67
- front tab's first prompt, and its sessions are on the list too, just under
68
- it. Enter opens the highlighted session in the same window and Esc leaves
69
- things as they were. Enter on a window opens its tabs beside those open, at
70
- the end of the strip, with its front tab in front; one already open is not
71
- opened twice, and a front tab no prompt went to gives its place. A window
72
- that would take more than nine tabs opens none, and the status line says
73
- how many to close. ctrl+a lists every directory's, as Claude Code's does,
74
- each row naming its directory from `~` (a window's front tab's, `+1` for
75
- each other directory its tabs work in), and ctrl+a again goes back to this
76
- one. A session or window from another directory is not opened in this
77
- window, whose settings, MCP servers and files are that directory's; chord
78
- says so and gives the `chord <agent> --resume <id>` or
79
- `chord --resume w-<id>` that opens it where it works.
80
-
81
- `chord --resume` with no id opens the same picker before any agent starts,
82
- as `claude --resume` does; Enter opens what it picks, from any directory,
83
- as its own `--resume` would, and Esc quits with nothing started.
84
-
85
- ctrl+x c opens another session of the same agent in the same directory,
86
- in front, beside the one already open, up to nine; `/new` does the same, and
87
- `/new codex` opens one of the agent it names, on that agent's command, model
88
- and mode from the settings files; `/new ` and part of a name lists the agents
89
- chord can start, those only your settings name among them, an agent whose own
90
- CLI is not on your `PATH` marked so, and Tab or Enter picks one. An agent chord cannot start is refused in
91
- the transcript, and a tenth session on the status line. With two or more open the
92
- window's top row has a tab for each, the one in front in inverse; a tab behind marks a
93
- turn running (`✻`), a reply not yet seen (`✓`), a failure (`✗`) or a
94
- permission or form waiting (`●`). ctrl+x n and ctrl+x p go to the next and
95
- the previous tab, ctrl+x 1 to 9 to a tab by its number, each with its own
96
- transcript, draft and prompt as it was left. After ctrl+x the status line
97
- names the keys that can follow, and Esc lets it go. A session behind that
98
- asks for permission or a form, or ends its turn, never comes to the front by
99
- itself: the status line says so
100
- (`● 2 claude needs your permission · ctrl+x a`), and ctrl+x a goes to the one
101
- that has waited longest, then the next on each press. ctrl+x k closes the
102
- session in front, the one to its left coming forward; one that is working
103
- or running a `!` command, waits on you, has prompts queued, or task agents
104
- running or long-lived agents working or waiting asks for a
105
- second ctrl+x k first, and its command stops with it. Its long-lived agents
106
- close with it. Closing the last one
107
- quits. With several open and any of them busy, ctrl+d
108
- and `/exit` ask for a second press too and name the busy ones. Quitting
109
- closes every session, waits for each agent to exit, and prints a
110
- `chord <agent> --resume <id>` for the session a prompt went to. With two or
111
- more such sessions it saves the window instead
112
- (`~/.local/state/chord/windows/`) and prints one command for all of them,
113
- `chord --resume w-<id>`, which opens every tab again in its order, each on
114
- its own agent where it works, the one that was in front in front. A window
115
- opened that way and quit again is saved over its own record, as it is then.
116
- A tab whose session record has gone is left out, and the status line says
117
- which; a window id goes on its own, never among session ids.
118
-
119
- A resumed session shows its earlier prompts, replies and tool calls, an
120
- edit with its diff, and the next prompt goes on in the same session. chord
121
- keeps a record of every session a prompt was sent in, in its state directory
122
- (`~/.local/state/chord/records/`), which `--continue`, `--resume` and
123
- `/resume` read, and the past is drawn from it whichever way the agent
124
- reopens the session. The id is the agent's own: for Claude Code, the one
125
- `claude --resume` takes, so `--resume <id>` also opens a session chord never
126
- saw, its past as the agent replays it.
127
-
128
- `--resume` (`-r`), given once per id, takes up to nine, the most one window
129
- holds, and opens each
130
- in a tab of its own, in the order given, the first in front. Each tab runs
131
- its session's own agent in its session's own directory, with that
132
- directory's settings and MCP servers; `@`, `!` commands, `/status` and the
133
- header follow the tab in front, and ctrl+x c and `/new` open beside it in
134
- its directory. Several ids open only sessions chord has a record of: an
135
- unknown id, the same id twice or a tenth refuses the whole command before
136
- the window opens. Each `--resume` takes one id or none, so the agent goes
137
- anywhere around them: `chord codex -r <id> -r <id>`. As the id is optional,
138
- a word after `--resume` that names one of chord's own flags (`model`, `c`)
139
- is not read as an id.
140
-
141
- ctrl+g opens the prompt in your editor (`$VISUAL`, then `$EDITOR`, then
142
- `vi`), run through your shell; what it saves comes back as the prompt when
143
- it exits. An editor that exits with an error or is killed leaves the
144
- prompt as it was, and the status line says so.
145
-
146
- ctrl+v puts the image on the clipboard into the prompt as `[Image #1]`, at
147
- the cursor, and Enter sends it after the text. So does the terminal's own
148
- paste (cmd+V) where the terminal sends an empty paste for a clipboard that
149
- holds only an image, as Ghostty does; one with nothing on the clipboard
150
- changes nothing. A path to a PNG, JPEG, GIF
151
- or WebP file pasted or typed into the prompt (`/…`, `~/…`, `file://…`, as a
152
- terminal writes a dropped file) is taken the same way. Backspace after
153
- the placeholder, or delete before it, takes it whole, and the image stays
154
- behind. An agent that says it takes no
155
- images gets none, and the status line says so.
156
-
157
- `/config` lists the agent's own settings for the session other than its
158
- model and mode, such as Claude's effort, each with its value; Enter on one
159
- lists its values and Enter on a value sets it.
160
-
161
- Each session's transcript opens with a header: Chorded's mark in its
162
- gradient, drawn in half blocks, and beside it chord's version, the agent and
163
- the model the session started on, its directory and the keys to `?` and
164
- `/help`; a resumed session's says when it was last used and its first
165
- prompt. It stands at the top, the window's first row with one session open
166
- and under the row of tabs with more, and the conversation grows down from it;
167
- once the conversation fills the window the header scrolls away, and `home`
168
- brings it back.
169
-
170
- `/theme` chooses chord's colours: Auto, Dark, Light, each of those two
171
- colour-blind friendly, or in the terminal's own 16 colours. Moving through
172
- the list shows the whole window in the highlighted theme; Enter keeps it and
173
- saves it to your settings file, and Esc goes back. Auto, the default, asks
174
- the terminal for its background as chord starts. chord never colours plain
175
- text, so it stays your terminal's own, and `NO_COLOR` turns every colour off
176
- whatever the theme.
177
-
178
- `/vim` turns vim mode on for the prompt, and off again; the choice is kept
179
- for the next start. The box starts in insert mode, where it types as ever,
180
- and `-- INSERT --` or `-- NORMAL --` under it says which mode it is in. Esc
181
- goes to normal mode, which takes `h j k l`, `w b e`, `0 $ ^`, `x`, `dd`,
182
- `dw`, `cw`, `D`, `C`, `i a I A o O`, `u`, `p` and counts such as `3w` or
183
- `d2w`; an `[Image #N]` goes whole under `x` and `dw`. Enter sends from
184
- either mode. Esc in normal mode does what it does without vim mode, so
185
- interrupting a turn takes Esc twice from insert mode; an open list, picker
186
- or panel still closes on the first Esc.
187
-
188
- `-p` draws no window: it sends one prompt, with anything piped in after it
189
- on a line of its own, writes the reply to stdout as it streams, and exits 0
190
- when the agent ends its turn, or 1 with the error on stderr. Nobody is there
191
- to answer a permission, so each one is refused and stderr says so.
192
- `--permission-mode`, or `permissionMode` in the settings files, starts the
193
- turn in that mode, and `--effort`, or `effort`, on that effort; one the
194
- agent does not take is a `chord: could not start in <mode> mode, …` or
195
- `chord: could not start on <effort> effort, …` line on stderr, and the turn
196
- runs as the agent chose. `--dangerously-skip-permissions`, only with `-p` and never a setting,
197
- allows every permission instead, each with a `chord: allowed <title>.` line
198
- on stderr; with both, the mode is asked for and whatever the agent still asks
199
- is allowed.
200
- `--output-format json` prints one object at the end instead: `result`,
201
- `session_id` (which `--resume` takes), `stop_reason`, `is_error`, and `usage`
202
- and `total_cost_usd` when the agent reports them. An agent that reports its
203
- tokens but no cost, as Codex can, gets a cost chord works out from the
204
- model's price, with `cost_estimated: true` beside it; `/cost` says
205
- `(chord's estimate)` after such a cost, and a context window chord took from
206
- the model's data is marked `~` on the status line.
207
-
208
- ## Settings
209
-
210
- chord reads two settings files before it starts: the user's,
211
- `~/.config/chord/settings.json` (under `$XDG_CONFIG_HOME` when that is set),
212
- and the project's, `.chord/settings.json` in the directory the session works
213
- in. The project's file overrides the user's, and a command-line flag overrides
214
- both.
215
-
216
- ```json
217
- {
218
- "agent": "codex",
219
- "agents": {
220
- "claude": { "effort": "high", "permissionMode": "plan" },
221
- "my-agent": { "command": "my-agent --acp" }
222
- }
223
- }
224
- ```
132
+ Inside the window:
225
133
 
226
- | Key | Sets | Flag |
227
- | ------------------------------ | ---------------------------------------------------- | ------------------- |
228
- | `agent` | the agent `chord` starts when none is named | `[agent]` |
229
- | `agents.<name>.command` | the command that starts that agent instead of chord's own | `--agent-command` |
230
- | `agents.<name>.model` | the model each of its sessions starts on | `-m, --model` |
231
- | `agents.<name>.effort` | the effort each of its sessions starts on | `--effort` |
232
- | `agents.<name>.permissionMode` | the mode each of its sessions starts in | `--permission-mode` |
233
- | `preferredNotifChannel` | how the terminal is told chord waits on you | |
234
- | `theme` | chord's colours, as `/theme` chooses them; user's file only | `/theme` |
235
- | `editorMode` | `vim` for vim mode in the prompt, as `/vim` leaves it; user's file only | `/vim` |
236
- | `mouse` | `false` leaves the mouse to the terminal; user's file only | |
237
- | `mcpServers` | MCP servers handed to the agent, as `.mcp.json` writes them | |
238
-
239
- When a turn ends, a permission is asked or the agent asks you to fill in a form
240
- or open a link, chord tells the terminal, so a window in the background can say
241
- so. `preferredNotifChannel` is `auto` by default: OSC 9, a desktop
242
- notification, in iTerm2, WezTerm, Ghostty and kitty;
243
- OSC 777 in foot; the bell elsewhere and inside tmux. `bell`, `osc9`, `osc777`
244
- choose one, and `off` turns it off. A turn you interrupt with Esc is not
245
- announced. With several sessions open, the notification names the tab:
246
- `fake (2) needs your permission: Write notes.txt`.
247
-
248
- `theme` takes Claude Code's ids: `auto` (the default), `dark`, `light`,
249
- `dark-daltonized`, `light-daltonized`, `dark-ansi` and `light-ansi`. It is
250
- about your terminal and your eyes rather than a project, so it is read only
251
- from the user's file, and one in a project's file is reported and left out.
252
- `/theme` writes it there, keeping the file's other keys. `editorMode`,
253
- `normal` (the default) or `vim` as Claude Code names them, is read from the
254
- user's file alone for the same reason, and `/vim` writes it there the same
255
- way.
256
-
257
- chord reads the mouse, so the wheel and the trackpad scroll the
258
- transcript, as pgup, pgdn and shift+↑/↓ do, and ↑/↓ stay with your earlier
259
- prompts. To select text, hold your terminal's modifier while you drag:
260
- option in iTerm2, fn in Terminal.app (or turn mouse reporting off with
261
- ⌘R), shift in most others. Inside tmux, the wheel reaches chord only with
262
- `set -g mouse on`; without it the terminal sends ↑/↓. `"mouse": false`, read
263
- from the user's file only, leaves the mouse to the terminal, as before.
264
-
265
- ### Keybindings
266
-
267
- `~/.config/chord/keybindings.json`, beside the settings file, rebinds
268
- chord's keys. It has the shape of Claude Code's `~/.claude/keybindings.json`
269
- and the same action names, so a block copied from there means the same
270
- here; chord never reads Claude Code's file itself.
271
-
272
- ```json
273
- {
274
- "bindings": [
275
- {
276
- "context": "Chat",
277
- "bindings": {
278
- "enter": "chat:newline",
279
- "ctrl+s": "chat:submit",
280
- "ctrl+g": null,
281
- "ctrl+x ctrl+e": "chat:externalEditor"
282
- }
283
- }
284
- ]
285
- }
286
- ```
134
+ | Key | Does |
135
+ | ----------------- | -------------------------------------------- |
136
+ | `?` | every key, on an empty prompt |
137
+ | `/` | slash commands, chord's and the agent's |
138
+ | `@` | mention a file |
139
+ | `!` | run a shell command, its output for the agent |
140
+ | `shift+tab` | cycle the permission mode |
141
+ | `ctrl+o` | expand tool calls and subagents |
142
+ | `ctrl+x c` / `/new codex` | open another session as a tab |
143
+ | `ctrl+x 1`…`9` | go to a tab |
144
+ | `esc` | interrupt the turn |
287
145
 
288
- A key bound in a context replaces what it did there, `null` takes it away,
289
- and a chord is keys separated by spaces, each within 3 seconds of the one
290
- before. The actions are `chat:submit`, `chat:newline`, `chat:cancel`,
291
- `chat:cycleMode`, `chat:externalEditor`, `chat:imagePaste`,
292
- `history:previous`, `history:next` and `help:toggle` in `Chat`;
293
- `app:toggleTranscript`, `history:search`, and chord's own `session:new`,
294
- `session:next`, `session:previous`, `session:goto1` to `session:goto9`,
295
- `session:list`, `session:attention` and `session:close` in `Global`;
296
- chord's own `agents:close` (`x`) in `Agents`, the list of a session's
297
- agents and monitors, where it closes an agent or stops a monitor;
298
- `autocomplete:accept`, `dismiss`, `previous` and `next` in `Autocomplete`;
299
- `historySearch:next`, `accept` and `cancel` in `HistorySearch`;
300
- `confirm:no` in `Confirmation`; `help:dismiss` in `Help`; `select:cancel`
301
- and `select:toggleScope` (`/resume`'s ctrl+a, chord's own name) in `Select`; and `scroll:pageUp`, `pageDown`, `lineUp`, `lineDown`, `top`
302
- and `bottom` in `Scroll`. ctrl+c and ctrl+d cannot be rebound, nor can the
303
- keys inside lists, forms and vim mode. An unknown context, action or key,
304
- and a key that would mean two actions at once, such as a key the
305
- transcript scrolls on bound in `Chat`, is left out and named as a
306
- warning in the transcript and on stderr, and the status line counts them; the
307
- rest of the file still applies. The `?` panel and the hints name the keys as
308
- bound, and `\ + enter for a newline` names the key that sends.
309
-
310
- The keys work on a Russian layout too, the defaults and the file's alike: a
311
- press that does nothing as typed is read as the US key in the same place,
312
- so ctrl+ч is ctrl+x, `с` after it opens a session and vim's normal mode
313
- moves on р о л д. Text is never read again: Cyrillic typed in the prompt,
314
- a form, the search line or vim's insert mode stays as typed, and a key the
315
- file binds in Cyrillic is its own. Punctuation a US layout also types stays
316
- itself, so on "Russian – PC", where the key in `?`'s place types `,`,
317
- shift+7's `?` opens the panel. In a terminal speaking the kitty keyboard
318
- protocol (kitty, Ghostty, WezTerm, iTerm2 with CSI u on), every key is
319
- found on any layout, Greek, Ukrainian or Hebrew as well, by the key in its
320
- place that the terminal names, so there the key in `?`'s place opens the
321
- panel on an empty prompt too, and types its `,` after a draft.
322
-
323
- chord hands the agent MCP servers for each session it opens, new or
324
- resumed, from three places, each over the one before: `mcpServers` in the
325
- user's settings file, the `.mcp.json` in the directory the session works in
326
- (the file Claude Code and other tools share), and `mcpServers` in the
327
- project's `.chord/settings.json`. A server named twice is the later one,
328
- whole. Each is written the way `.mcp.json` writes it:
329
-
330
- ```json
331
- {
332
- "mcpServers": {
333
- "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "."], "env": { "DEBUG": "1" } },
334
- "docs": { "type": "http", "url": "https://mcp.example.com/mcp", "headers": { "Authorization": "Bearer …" } }
335
- }
336
- }
337
- ```
146
+ Settings live in `~/.config/chord/settings.json` and the project's
147
+ `.chord/settings.json`: the default agent, each agent's model, effort and
148
+ mode, MCP servers, theme and notifications.
338
149
 
339
- A server started as a command has `command`, and may have `args` and `env`;
340
- one reached over the network has `type` (`http` or `sse`), `url`, and may
341
- have `headers`. `/mcp` lists the servers chord passed: each one's name, its
342
- transport, its command or URL, and the file that defined it; Esc closes it.
343
- It does not show `env` or `headers`. Whether the agent then connected to
344
- them, ACP does not say, and neither does `/mcp`. chord only reads these
345
- files; it never writes `.mcp.json` or the agent's own configuration. A
346
- server that is wrong is named with its file and left out, and the others
347
- still count; a `.mcp.json` that is not a JSON object is named and ignored.
348
- `/mcp` says under its list how many servers each file lost that way.
349
- `-p` passes the same servers.
350
-
351
- Beside them, every session the window opens gets an MCP server of chord's
352
- own, named `chord` (or `chord-2`, … where one of the user's already is), where
353
- its agent takes MCP over HTTP: chord serves it on
354
- the loopback while the window is open, and each session reaches it with a
355
- token of its own, so nothing else on the machine can call it. Its tools let
356
- an agent see what it could start: `list_agents` names every agent chord can
357
- start and the models and modes of those already read, or, given an agent's
358
- name, that one's, starting it briefly to read them if no session of it is
359
- open;
360
- `list_sessions` names the window's open sessions with their agent, model and
361
- tab. `spawn_task` starts a task agent: another agent, on any runtime chord
362
- knows and a model it offers, does one job with no tab of its own. Its work
363
- draws in its parent's turn as a subagent's block does, `Agent(<name>) ·
364
- codex · gpt-5.3-codex`, its permission requests, forms and links come to you
365
- in the parent's tab, and what it tells its parent with `send_message`, its
366
- one tool, and the report its first turn ends with reach the parent as
367
- messages, drawn as a `←` row: a turn of the parent's, or, while one runs,
368
- what the task tells it goes into that turn, and the report waits behind it
369
- the way a prompt does. Every agent chord opens but a task has `spawn_task` and
370
- `list_agents`, so a long-lived child starts task agents of its own, drawn in
371
- its own turn and closed with it; a task starts none. Esc stops the turn's
372
- task agents with it, and they
373
- send no report; `/clear` closes them with the session it lets go. A task
374
- asked for a model its runtime refuses fails before it starts work. Asked
375
- for an effort too, as `list_agents` lists them, it starts on it, and its
376
- block says it after the model; one the runtime does not take leaves it on
377
- the runtime's own, which the block says instead, and the refusal is a line
378
- in the parent's transcript and in the answer, which waits for the task to
379
- be up.
380
-
381
- `open_agent` opens a long-lived agent the same way, with the prompt as its
382
- first turn, a message from `main`. It gets no tab: while a session has one,
383
- a list of its agents sits under the status line, `main` and each child in
384
- the order it opened, each child in a colour of its own, with its runtime,
385
- model, the effort it is on (`open_agent` takes one as `spawn_task` does)
386
- and state (`✻ working 41s`, `● permission 12s`, `← message from
387
- @main`, `✓ replied 2m ago`). ↓ on an empty prompt that is not walking
388
- history moves into the list, where ↑ ↓ or j k pick; Enter or Esc goes back
389
- to the box with the pick kept. The picked agent's chat fills the window,
390
- the box takes its colour and its name on the top border, and the status line
391
- its model, effort and context: what you type goes to it as your own prompt. `send_message` from the parent reaches a
392
- child, and from a child its parent alone, each a turn of the recipient's,
393
- as many as they trade; `list_sessions` gives each session's children. A
394
- message to an agent that is working goes into its turn at once, where its
395
- runtime takes that (Claude's and Codex's adapters advertise ACP's
396
- `_session/steering`), and draws there, among the turn's calls; while the
397
- turn waits on your answer to a permission, form or link, it waits under the
398
- working line as `← @main · after your answer: …` and goes in once you
399
- answer. A runtime without steering takes it as the next turn, as the queue
400
- under the working line shows. Should the message reach the agent just as
401
- its turn ended, and the agent start a turn of its own with it, as Codex's
402
- adapter does, chord cancels that turn at once, closes it with a dim
403
- `Interrupted · the agent started this on its own` line, and sends the
404
- message as the next turn. A monitor's events and your own prompts
405
- always wait for the turn's end. A
406
- child that waits on you is named on the status line, ctrl+x a picks it, and
407
- its permission box opens there. `x` in the list closes the picked child, a
408
- second time while it works or waits, and chord tells the parent so;
409
- `close_agent` closes one from the parent, and a message to a closed one is
410
- refused. A child whose agent exits, or whose turn fails, is news to its
411
- parent too: a `← chord` message, a turn of the parent's, says
412
- `parser's agent exited: <the end of its stderr>. open_agent opens it
413
- again.`, or that its turn failed and why, so a parent waiting on a report
414
- does not wait for ever. A session holds eight children at most, a team's
415
- lead counting as one and its members as none. `/clear` with a child
416
- picked is refused; on `main` it closes the children with the session.
417
-
418
- A team saved in `.chord/teams/<name>.md`, or in `teams/` beside your
419
- settings file for every project, takes a job from the session you talk to:
420
- say "hand it to bugfix" and the agent calls `run_team`, which chord draws
421
- as `Team(bugfix) · claude · opus` with the job under it. `list_teams` names
422
- the saved teams and their runs open. The team's lead is a long-lived child
423
- named after the team, on the lead's runtime, model, effort and mode; a second run
424
- of a running team is `bugfix 2`. Its first prompt is the team's
425
- instructions, drawn as one line (`bugfix's instructions for the lead · 58
426
- lines`, ctrl+o for all of them), then the job as a message from `@main`.
427
- The lead's `open_agent` takes a member's name and opens only the file's
428
- members, on the file's runtime, model, effort and mode (`Open(tester) ·
429
- claude · sonnet · high · acceptEdits`); an effort the runtime does not take
430
- leaves the agent on its own, which the answer and the agent's transcript
431
- say; its `send_message` reaches main, its members and
432
- the other runs' leads, and each message to main is a turn of main's. A
433
- member messages its lead and the team's other open members by name,
434
- directly. In the list the lead's row reads `team · claude · Opus` and its
435
- open members are nested under it (`├─ tester`); when the list does not fit
436
- its rows, each team folds to its lead's row, `team · claude · 4 agents` and
437
- its most urgent state with the member's name (`● tester: permission 12s`),
438
- and the team you are in unfolds. A member picked has its box read `tester ·
439
- bugfix`; its permissions are yours to answer, as a child's are, the
440
- notification says `tester (bugfix) needs your permission`, and with two
441
- runs open the status line says which run's `tester` asks. `x` on a lead
442
- closes the team, members and all, twice while any of it works, and chord
443
- tells main; a member closed tells the lead, and a lead whose agent exits
444
- closes its members and tells main.
445
-
446
- A team is made by asking for one: the agent you talk to calls
447
- `propose_team`, and chord draws its proposal as `Team(bugfix) · proposal`,
448
- a row per agent with its runtime, model, effort where any agent sets one,
449
- mode and role, each mode whole and
450
- one that skips your ok in the warning colour, then how the team works,
451
- folded. A box shaped like the permission box asks `Save team bugfix?`: for
452
- this project (`.chord/teams/bugfix.md`), for every project
453
- (`~/.config/chord/teams/bugfix.md`), or no, tell the agent what to change,
454
- which Esc picks too. chord writes the file, never the agent; the call ends
455
- `Saved to …` or `Not saved`, and your next words go to the agent. A
456
- proposal under a saved team's name is `Team(bugfix) · change`, its changed
457
- rows marked, a changed effort or mode with the one it had (`high was
458
- medium`), and its body's change
459
- counted and drawn as a diff (whole with ctrl+o), and saves back in place.
460
-
461
- `/team` is chord's own command for teams, and talks to the session you
462
- opened whatever agent is picked. `/team` alone (or `/team list`) opens the
463
- teams picker: each saved team with its size and runtimes, where it is
464
- saved, `✻ working 6m` or `✻ 2 runs` while it runs in the window, and its
465
- description, and a file that is not a team with its first problem. Enter
466
- puts `/team run bugfix ` in the box for you to type the job. `/team new
467
- <words>` asks the agent for a team through `propose_team`; to change one,
468
- ask the agent in plain words, and it proposes the change against the saved
469
- team through the same tool. `/team show bugfix`
470
- reports the team under the command, and while it runs each agent's state
471
- and latest call or message. `/team run bugfix <job>` hands it your words as
472
- they are, drawn as `run_team`'s `Team(bugfix)` row, with no turn of the
473
- agent's; the agent hears of it with your next prompt. `/team stop bugfix`
474
- closes that run and its members at once, and chord tells the agent. A
475
- team's name is completed after `show`, `run` and `stop`.
476
-
477
- `monitor` runs a command in the background for the agent that asks, a
478
- session's or a long-lived child's, and each batch of lines it prints reaches
479
- that agent later as a message: a turn of its own, drawn `← dev server errors
480
- · monitor` with the lines as printed, folded after six. Its end is one more,
481
- `· exit code 1`, `· timed out`, `· flooded` or `· stopped`, with chord's
482
- sentence last. While one runs it is a row in the list under the prompt, after
483
- the agents, with its command and how long it has run, a child's ending with
484
- its name; ↓ reaches it, and `x` on it stops it at once. A turn an event
485
- started does not ring the terminal when it ends. `stop_monitor` and
486
- `list_monitors` are the agent's own, and a resumed session draws its events
487
- again and names the monitors it left running, which are not restarted.
488
-
489
- A session resumed after its agents ran draws them as they were: each task
490
- agent's block, its work behind ctrl+o (read from the task's own record,
491
- so a task whose record was deleted keeps its block and how long it ran,
492
- without the work), a
493
- task still running when the
494
- session was left ending `Disconnected`, every message both ways, and the
495
- `Open`, `Close` and `→` calls. Its long-lived agents are not reopened with
496
- it; a closing line names those still open when it was left, which
497
- `/resume` lists like any session, and a message the parent sends one is
498
- refused. Opened from `/resume`, such a child is your own session, in a tab,
499
- with no parent to message. A team run is one of them, named with how many of
500
- its agents were open (`team bugfix (4 agents)`), and the line ends with
501
- `/team run bugfix starts the team again`: a fresh run, with no memory of
502
- the last but the working tree and what main was told. `/resume` lists its
503
- lead and members like any child. A task agent gets no command on quit.
504
- chord's own calls draw as `List agents`, `List sessions`, `Open(parser)`
505
- and `Close(parser)`, and a message sent as `→ @main` or `→ @parser`, never as
506
- their MCP names. A name after an arrow takes `@` where `send_message` reaches
507
- it, `main` and a long-lived child; a task, named by its title, and chord's
508
- own `← chord` stay bare. `/mcp` lists chord's server first,
509
- and says what it gives the agent, or that the agent does not take HTTP and
510
- got none. `-p` gets no such server.
511
-
512
- Models, efforts and modes are set per agent because their ids are the
513
- agent's own: `/model`, `/config` and shift+tab show what an agent offers, and
514
- `chord agents` lists the names. An effort is one the model the session starts
515
- on offers. A starting model, effort or mode the agent refuses is said in the
516
- transcript, with where it was set and what the agent offers, and the session
517
- goes on as the agent chose; an agent with no effort starts on its own, and
518
- the line says it offers none. An unknown key, or a key with the wrong kind of value, is
519
- named with its file and left out, and the rest of the file still counts; a
520
- file that is not a JSON object is named and ignored. Either way chord starts:
521
- the problem is a line on stderr and a yellow line at the top of the
522
- transcript. `-p` takes `agent`, `command`, `effort` and `permissionMode`
523
- from the files, and says a refused effort or mode on stderr; `--model` is for
524
- the window. `--agent-command`, `--model`, `--effort` and `--permission-mode`
525
- speak for the agent the command line names: a session `/new` opens of another agent starts on that
526
- agent's settings alone.
527
-
528
- chord knows the agents the [ACP Registry](https://agentclientprotocol.com/registry)
529
- offers through npx or uvx, each at the version chord's source pins: `claude`
530
- and `codex` for Claude's and Codex's adapters, every other one by its
531
- registry id. It starts one as `npx -y <package>@<version>` or
532
- `uvx <package>@<version>`, so `npx` or `uvx` must be on your `PATH`.
533
-
534
- Some agents ship their own CLI, which speaks ACP itself: `cursor`, `devin`,
535
- `fx`, `goose`, `junie`, `kimi`, `kiro`, `openclaw`, `opencode`, `poolside`
536
- and `zeroclaw`. chord starts each by the command its docs give (Cursor's
537
- `agent acp`, goose's `goose acp`, …), which you install yourself; when it is
538
- not on your `PATH`, chord says which command it looked for and where the
539
- agent says to install it, and exits before the window. chord downloads
540
- nothing for them: the registry also offers most of these as archives to
541
- unpack, but a CLI you installed and keep up to date is the one you already
542
- signed in to. Any other ACP agent starts with `agents.<name>.command` or
543
- `--agent-command`, which also replace the command chord knows for a name; a
544
- name your settings files alone give a command starts as `chord <name>` and
545
- opens with `/new <name>`. `chord agents` lists them all: each one's name and
546
- title (`from settings` for a name only they define), `npx` or `uvx` for the
547
- registry's, `own CLI · found` or `own CLI · not on PATH` for those that need
548
- their own CLI, and `settings` where a settings file's command starts it, then
549
- what starts it, that command in the table's or the registry's place, wrapped
550
- within its column on a terminal and one line per agent when piped.
551
- You sign in to the agent the way it expects: chord starts the agent's ACP
552
- adapter or CLI, it does not sign you in to anybody.
553
-
554
- ## Development
150
+ **[The guide](docs/guide.md)** has everything else: every flag, setting, key,
151
+ the team file format, chord's MCP tools for agents, and how sessions are
152
+ recorded.
555
153
 
556
- ```sh
557
- bun install # the dependencies
558
- bun run chord # run from source
559
- bun run check # types, lint, format, tests — must pass before every commit
560
- bun run compile # this machine's binary into dist/
561
- bun run registry # refetch the ACP Registry's agents into src/registry.ts
562
- ```
154
+ ## Supported agents
563
155
 
564
- `CLAUDE.md` is how the code is written and is binding for people and agents
565
- alike. `docs/decisions.md` records why the stack is what it is.
156
+ Claude Code, Codex, Gemini CLI, GitHub Copilot, Cursor, OpenCode, Cline, Qwen
157
+ Code, Kimi Code, Kiro, Goose, Junie, Factory Droid, Auggie, Kilo, Devin, fx
158
+ and more: `chord agents` prints the full list, and any other ACP agent runs
159
+ with `chord --agent-command "my-agent --acp"`.
566
160
 
567
- A chord that has grown large: `kill -USR2 <pid>` writes a heap snapshot of
568
- it, without stopping it, into `heaps/` in chord's state directory, for
569
- Chrome's DevTools. `docs/memory.md` has how, and the long-run memory check
570
- (`bun scripts/memory.ts`).
161
+ ## Contributing
571
162
 
572
- ## Built on
163
+ Issues and pull requests are welcome. [CONTRIBUTING.md](CONTRIBUTING.md) has
164
+ how to run chord from source against its scripted test agent, choose checks
165
+ for a change, and follow the code conventions. Found a security issue?
166
+ See [SECURITY.md](SECURITY.md).
573
167
 
574
- - [ACP Registry](https://cdn.agentclientprotocol.com/registry/v1/latest/registry.json)
575
- — the agents chord knows by name, frozen into `src/registry.ts`, beside
576
- `src/clis.ts`'s agents started by their own CLI.
577
- - [OpenTUI](https://github.com/anomalyco/opentui) — the terminal interface, through
578
- its React bindings.
579
- - [Agent Client Protocol SDK](https://github.com/agentclientprotocol/typescript-sdk)
580
- — the connection to the agent, and the protocol types.
581
- - [Cliffy](https://cliffy.io) — the command line.
168
+ The screenshots above are chord itself, run against that test agent and
169
+ captured by `bun run screenshots`.
582
170
 
583
171
  ## Licence
584
172
 
585
- chord's code is [MIT](LICENSE).
173
+ chord's code is [MIT](LICENSE). The Chorded name and the chevron mark are
174
+ trademarks of Igor Katsuba and are not covered by the licence; a fork should
175
+ draw its own ([TRADEMARKS.md](TRADEMARKS.md)).
586
176
 
587
- The Chorded name and the chevron mark, which chord draws at the top of a
588
- session (`scripts/mark.svg`, and `src/ui/header/mark.ts` generated from it), are
589
- trademarks of Igor Katsuba. The MIT licence does not cover them: a fork may
590
- keep the code, but should take the mark out and draw its own. See
591
- [TRADEMARKS.md](TRADEMARKS.md).
177
+ chord is the open sibling of [Chorded](https://chorded.app), a native macOS
178
+ workspace for agent sessions driven by key chords.
package/package.json CHANGED
@@ -1,12 +1,26 @@
1
1
  {
2
2
  "name": "@chorded/chord",
3
- "version": "0.54.0",
3
+ "version": "0.55.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/IKatsuba/chord.git"
8
8
  },
9
+ "homepage": "https://github.com/IKatsuba/chord#readme",
10
+ "bugs": {
11
+ "url": "https://github.com/IKatsuba/chord/issues"
12
+ },
9
13
  "description": "A full-screen terminal client for ACP coding agents.",
14
+ "keywords": [
15
+ "acp",
16
+ "agent-client-protocol",
17
+ "claude-code",
18
+ "codex",
19
+ "gemini-cli",
20
+ "coding-agent",
21
+ "terminal",
22
+ "tui"
23
+ ],
10
24
  "bin": {
11
25
  "chord": "bin/chord.js"
12
26
  },
@@ -14,9 +28,9 @@
14
28
  "bin/"
15
29
  ],
16
30
  "optionalDependencies": {
17
- "@chorded/chord-darwin-arm64": "0.54.0",
18
- "@chorded/chord-darwin-x64": "0.54.0",
19
- "@chorded/chord-linux-x64": "0.54.0",
20
- "@chorded/chord-linux-arm64": "0.54.0"
31
+ "@chorded/chord-darwin-arm64": "0.55.0",
32
+ "@chorded/chord-darwin-x64": "0.55.0",
33
+ "@chorded/chord-linux-x64": "0.55.0",
34
+ "@chorded/chord-linux-arm64": "0.55.0"
21
35
  }
22
36
  }