teapot-coding-agent 0.15.6 → 0.15.8

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.
package/README.md CHANGED
@@ -1,301 +1,290 @@
1
1
  # teapot 🫖
2
2
 
3
- A lightweight harness for running many AI coding agents continuously — simpler
4
- and lighter than existing harnesses. No TUI. One small web server, a browser
5
- tab, and any number of long-running agents.
6
-
7
- ## Design principles
8
-
9
- - **TypeScript + Node.js**, small runtime dependency set (`hono`, `openai`,
10
- `@hono/node-server`, `ws`, `zod`, `@mozilla/readability` + `happy-dom` for
11
- `read_url`). Frontend-only libraries (SolidJS, xterm.js, shiki) are
12
- devDependencies — they're compiled into the static bundle under `public/`
13
- and never touch the server's runtime install.
14
- - **Idle cost ≈ 0**: no polling loops; everything is event-driven or driven by
15
- one 15-second scheduler tick. Verified: master sits at ~0% CPU when idle.
16
- - **No TUI** — Discord-style chat UI built with **SolidJS + Vite**
17
- (`frontend/`, built to `public/`): agents as channels, events flowing as chat
18
- messages, tool calls as compact embeds. Markdown is rendered by a hand-written,
19
- XSS-safe renderer (`frontend/md.js`)
20
- - **Integrated terminal** — humans get an interactive shell (xterm.js over
21
- WebSocket) inside the selected agent's workspace: inspect what the agent
22
- did, run tests, fix things alongside it. Zero native dependencies — the PTY
23
- comes from util-linux `script` when available (colors, line editing,
24
- ctrl+c), with a plain-pipe fallback elsewhere.
25
- - **Human-readable persistence** — append-only JSONL event logs you can read
26
- with `cat` / `jq`; goal & memory as plain Markdown files in git
27
-
28
- ## Quick start
29
-
30
- Requires Node.js **>= 24** (TypeScript is executed natively in dev mode).
31
-
32
- ### Install globally from npm
3
+ **A lightweight harness for running multiple autonomous AI coding agents in parallel, from your browser.**
33
4
 
34
- ```sh
35
- npm install -g teapot-coding-agent
36
- teapot
37
- # open http://localhost:7788 — the first-run wizard walks you through
38
- # provider → API key → model → first agent (writes config.json for you)
39
- ```
5
+ > Try it in 5 minutes → [Quick start](#-quick-start) · Details live in the [Reference](#-reference) section
6
+
7
+ [日本語版はこちら](README.ja.md)
40
8
 
41
- The global install puts a `teapot` binary on your PATH (it serves the compiled
42
- server plus the pre-built web UI — no build step, no repo checkout needed).
43
- Prefer hand-writing the config? Skip the wizard and drop an edited copy of
44
- [`teapot.config.example.json`](teapot.config.example.json) at the path below.
45
- Alternatives:
9
+ ---
10
+
11
+ ## 🚀 Quick start
12
+
13
+ ### 1. Install
14
+
15
+ Requires Node.js **24+**.
46
16
 
47
17
  ```sh
48
- npx teapot-coding-agent # run without installing
49
- teapot --port 8080 # CLI flags: --port/-p, --config/-c
50
- teapot ~/my-config.json # explicit config path
51
- TEAPOT_PORT=8080 teapot # env overrides work as usual
18
+ npm install -g teapot-coding-agent
52
19
  ```
53
20
 
54
- ### Run from a checkout (development)
21
+ ### 2. Run it
55
22
 
56
23
  ```sh
57
- pnpm install
58
- mkdir -p ~/.config/teapot-coding-agent
59
- cp teapot.config.example.json ~/.config/teapot-coding-agent/config.json # edit it
60
- pnpm dev # or: pnpm build && pnpm start
61
- # open http://localhost:7788
24
+ teapot
62
25
  ```
63
26
 
64
- Config lookup order: CLI arg → `$TEAPOT_CONFIG` →
65
- `~/.config/teapot-coding-agent/config.json` → `./teapot.config.json` (legacy).
66
- Data (event logs) goes to `~/.local/share/teapot-coding-agent` by default.
67
- Env overrides: `TEAPOT_PORT`, `TEAPOT_API_KEY`, `TEAPOT_BASE_URL`,
68
- `TEAPOT_MODEL`, `TEAPOT_CONFIG_DIR`, `TEAPOT_DATA_DIR`.
69
-
70
- ## Multiple providers
27
+ → Open **http://localhost:7788**. A **setup wizard** walks you through
28
+ provider → API key → model → first agent (it writes the config file for
29
+ you) — no hand-editing required.
71
30
 
72
- Agents are matched to named OpenAI-compatible providers:
31
+ <details>
32
+ <summary>Prefer writing the config yourself?</summary>
73
33
 
74
- ```jsonc
34
+ ```json
75
35
  {
76
36
  "providers": {
77
- "openrouter": { "baseUrl": "https://openrouter.ai/api/v1", "apiKey": "sk-or-..." },
78
- "orcarouter": { "baseUrl": "https://api.orcarouter.ai/v1", "apiKey": "sk-orca-...", "model": "orcarouter/auto" },
79
- "local": { "baseUrl": "http://localhost:8080/v1", "apiKey": "llama.cpp", "model": "local" }
37
+ "openrouter": {
38
+ "baseUrl": "https://openrouter.ai/api/v1",
39
+ "apiKey": "sk-or-your-key",
40
+ "model": "anthropic/claude-sonnet-4"
41
+ }
80
42
  },
81
43
  "defaultProvider": "openrouter",
82
44
  "agents": [
83
- { "id": "alpha", "workspace": "workspaces/alpha" }, // default provider
84
- { "id": "beta", "workspace": "workspaces/beta", "provider": "local" }, // local model
85
- { "id": "gamma", "workspace": "workspaces/gamma", "provider": "openrouter",
86
- "model": "anthropic/claude-sonnet-4" } // per-agent model
45
+ { "id": "main", "workspace": "/home/you/my-project" }
87
46
  ]
88
47
  }
89
48
  ```
90
49
 
91
- Per-agent inline `baseUrl`/`apiKey`/`model` override the provider entry. The
92
- first-run wizard and the settings modal ship quick-add presets for OpenRouter,
93
- OrcaRouter, OpenAI and a local llama.cpp server.
50
+ Save it at `~/.config/teapot-coding-agent/config.json` (or pass a path as
51
+ the first CLI arg / `$TEAPOT_CONFIG`). A full template lives in
52
+ [`teapot.config.example.json`](teapot.config.example.json). With a config
53
+ present the wizard is skipped and your agents start immediately.
94
54
 
95
- **OpenRouter app attribution**: requests to `openrouter.ai` endpoints
96
- automatically carry `HTTP-Referer` / `X-OpenRouter-Title` /
97
- `X-OpenRouter-Categories: programming-app`, so teapot's usage shows up in
98
- OpenRouter's public rankings & analytics — no config needed. Other providers
99
- receive no extra headers.
55
+ </details>
100
56
 
101
- ## Architecture
57
+ ### 3. Use it
102
58
 
59
+ - Click `#main` in the left panel (created by the wizard)
60
+ - Type an instruction in the composer (e.g. "Fix this bug and make the tests pass")
61
+ - The agent reads/writes files, runs bash, and works on its own
62
+
63
+ Handy keys: `t` terminal · `d` right panel · `/` commands · `Esc` interrupt
64
+
65
+ ---
66
+
67
+ ## 🤔 What is this?
68
+
69
+ One line: **a server that hosts several autonomous coding agents over any OpenAI-compatible API, operated from a browser.**
70
+
71
+ ```text
72
+ ├─ agent: android ── ~/projects/android-app
73
+ ├─ agent: kernel ── ~/projects/kernel
74
+ └─ agent: web ── ~/projects/film-sims-web
103
75
  ```
104
- master (Hono server, src/master.ts + src/server/api.ts)
105
- ├── Agent alpha (workspace A) ── JSONL event log
106
- ├── Agent beta (workspace B) ── JSONL event log
107
- └── scheduler tick (15s) → cron tasks → prompts on forked branches
108
- ```
109
76
 
110
- - **Agent** (`src/agent/agent.ts`): an async loop that alternates LLM turns and
111
- tool executions until the model stops calling tools, then auto-continues
112
- toward its goal. `ask_user` parks the loop in a `waiting` status until the
113
- operator replies. Stop/resume at any time via API/UI — stop aborts an
114
- in-flight LLM call immediately (AbortController). Runaway guards: turn cap
115
- per round, consecutive-tool-error cap, per-command timeouts.
116
- - **Context management (staged)**: each turn prefers the provider's real
117
- `prompt_tokens`; past ~60% of budget, old oversized tool outputs are pruned
118
- (recent window protected); past the budget (`contextTokenBudget`, default
119
- ~96k — auto-derived at 75% when a model's `contextWindowTokens` is known)
120
- older turns are summarized into dense continuation notes plus a
121
- "## Durable lessons" section harvested into memory.md. Cut points never
122
- split a tool_call/tool_result pair.
123
- - **Session persistence**: conversations are rebuilt from the JSONL log on
124
- first interaction (lazy — boot cost stays O(agents)), so agents resume
125
- mid-task across master restarts instead of starting blank. Restores replay
126
- byte-identical request payloads, keeping provider prefix caches warm.
127
- - **LLM** (`src/agent/llm.ts`): official `openai` npm client against any
128
- OpenAI-compatible endpoint (OpenRouter, OrcaRouter, vLLM, llama.cpp server...). Model is config,
129
- never hard-coded.
130
- - **Tools** (`src/agent/tools.ts`): provider-agnostic JSON-schema function specs —
131
- file work via `read_file` (numbered lines, grep-style `pattern` mode, negative
132
- offsets), `write_file`, `edit_file` (unique replacement, `replace_all`,
133
- whitespace-tolerant fallbacks with recovery hints), `apply_patch`
134
- (Codex-style multi-file add/update/rename/delete patches, validated
135
- atomically before writing) and `list_dir`; `bash` for git/builds/tests and
136
- quick bulk transforms; `read_url` fetches a web page's readable content
137
- (Mozilla Readability + happy-dom); plus meta tools `finish` / `ask_user` /
138
- `report_progress` / `get_goal` / `set_goal` / `get_todo` / `set_todo` /
139
- `read_memory` / `set_memory` / `get_feedback` / `add_feedback` /
140
- `record_decision` / `get_decisions` / `list_skills`. Paths are confined to
141
- the workspace (symlink-aware); bash runs detached in its own process group
142
- and the whole group is SIGKILLed on timeout or shutdown.
143
- - **Sub-agents** — an agent can `spawn_agent({task, context, persona?})` to
144
- delegate work: `context:"fork"` starts the child with a byte-exact copy of
145
- the parent's conversation prefix (provider prefix caches stay warm; stored
146
- as a reference header in the child's log — parent history is never copied),
147
- `"none"` starts fresh. Parents steer children via `message_agent`, check on
148
- them with `list_children`, and can bulk-stop them (`stop_children`,
149
- descendants included). Children mirror their activity into the parent's
150
- timeline tagged `@<id>`, and their finish/error reports are delivered back
151
- automatically. Nesting depth is capped by `maxSpawnDepth` (default 3).
152
- Default personas: reviewer/tester/researcher/implementer (+ read-only
153
- enforcement for researcher/reviewer), plus `@mention` spawning from the
154
- composer.
155
- - **Cache-friendly prompt design** — the system prompt is byte-identical on
156
- every turn; session state (goal, memory, skills) is fetched via tools, never
157
- injected. Combined with the append-only message history this keeps provider
158
- prefix caches hot, so long sessions pay incremental input prices instead of
159
- re-sending full context every turn.
160
- - **Session storage** — everything teapot manages lives under
161
- `<dataDir>/sessions/<sid>/` (`chat.jsonl`, `goal.md`, `todo.md`,
162
- `memory.md`, `feedback.md`, `decisions.md`), so agent workspaces stay
163
- clean. Each incarnation gets a fresh `<agentId>-<uuid>` directory (no
164
- history leaks across projects); restarts reuse the latest one. Legacy
165
- layouts are migrated automatically.
166
- - **Goal / knowledge** — goal + memory are harness-managed and read/written
167
- through tools (`get_goal` / `set_goal` / `read_memory` / `set_memory`);
168
- `AGENTS.md` is optional project knowledge in the workspace root that agents
169
- are told to read at session start. Nothing is seeded into your project.
170
- - **Decisions & feedback** — `record_decision(decision, rationale,
171
- alternatives?)` keeps the *why* behind choices in `decisions.md`
172
- (compaction forgets reasoning, this file doesn't); corrections become
173
- durable rules via `add_feedback(rule)` with repetition counts.
174
- - **Task list** — `todo.md` in the session dir, editable by BOTH sides:
175
- humans write it from the web UI (✅ tasks panel) or
176
- `POST /api/agents/:id/todo {text, notify?}`, the agent reads and updates it
177
- via `get_todo` / `set_todo`. Saving with notify queues a harness prompt so
178
- the agent picks up changes at the next turn boundary.
179
-
180
- ### Web UI
181
-
182
- - **Sessions as channels** — chat feed with live-streamed LLM output (💭
183
- reasoning collapsible), tool calls/results as expandable embeds, progress
184
- reports and state changes as dividers
185
- - **Deep links** — every session has a URL (`http://localhost:7788/session/<id>`);
186
- the last open session is remembered
187
- - **Details panel** (`d`) — session info, model switcher (provider select +
188
- OpenAI-compatible `GET /models` autocomplete; applies to the running
189
- session from the next turn), controls, goal editor, progress, runtime stats
190
- - **Terminal** (`t`) — interactive shell in the agent's workspace for humans,
191
- rendered with xterm.js over WebSocket
192
- - **Keyboard** — `↑`/`↓` switch sessions · `/` focus composer · `t` terminal ·
193
- `d` panel · `esc` interrupt a running agent
194
- - Realtime updates flow over WebSocket (`/api/ws`) with auto-reconnect
195
-
196
- ### Agent Skills
197
-
198
- Skills are reusable playbooks the agent loads on demand — and writes itself,
199
- so hard-won procedure knowledge survives sessions:
77
+ Each agent owns its own workspace and runs in parallel as a channel in a Discord-style UI. teapot is **not** a wrapper around Claude Code or Codex CLI — it implements its own agent loop (read_file / edit_file / apply_patch / bash / read_url / memory / skills).
78
+
79
+ ### When would I use it?
80
+
81
+ - Long-running self-directed tasks like *"triage every bug in this repo and fix them until tests pass"*
82
+ - **Different models per project** — heavy work on Sonnet, code review on a local Qwen
83
+ - Watch progress, goals and task lists in the browser while you do something else
84
+
85
+ ### How does it compare to CLI tools?
86
+
87
+ | | teapot | Claude Code & similar CLIs |
88
+ |---|---|---|
89
+ | Form | resident server + web UI | interactive terminal |
90
+ | Multiple agents | ✅ parallel | usually one session |
91
+ | Mixed models | ✅ per agent | fixed |
92
+ | Long-running work | ✅ auto-restores from JSONL logs | manual session juggling |
93
+ | Scheduled tasks (cron) | ✅ 15-second tick | ❌ |
94
+
95
+ ---
96
+
97
+ ## 🔧 Features
200
98
 
99
+ <details>
100
+ <summary><b>Goals &amp; autonomous loop</b></summary>
101
+
102
+ Set a goal and auto-continue keeps deciding whether to keep working after each round. Optionally attach a **verification contract** — when the agent calls `finish`, an independent auditor LLM checks the contract before "done" counts:
103
+
104
+ ```text
105
+ goal: "Add account deletion to the auth module"
106
+ verify: "npm test passes with zero failures / README documents the endpoint"
107
+ ↓ on finish
108
+ independent audit → approved ⇒ done · changes-required ⇒ gaps queued back to the worker
201
109
  ```
202
- <workspace>/skills/<name>/SKILL.md # project skills (git-friendly)
203
- ~/.config/teapot-coding-agent/skills/<name>/SKILL.md # shared across agents
110
+
111
+ </details>
112
+
113
+ <details>
114
+ <summary><b>Sub-agents</b></summary>
115
+
116
+ Spawn sub-agents with `@persona <task>` mentions. Children can fork the parent conversation by reference, so provider prefix caches stay warm. `wait_children` parks the parent until a child settles; its report lands in the parent's timeline. Nesting cap via `maxSpawnDepth` (default 3).
117
+
118
+ </details>
119
+
120
+ <details>
121
+ <summary><b>Memory / task list / skills</b></summary>
122
+
123
+ - **memory.md** — durable notes per session (set_memory / get_memory)
124
+ - **todo.md** — checklist shared with the operator; supports surgical per-item updates
125
+ - **skills** — reusable playbooks stored globally (`~/.config/teapot-coding-agent/skills/`) or per workspace; workspace versions shadow global ones
126
+
127
+ </details>
128
+
129
+ <details>
130
+ <summary><b>Scheduled tasks (cron)</b></summary>
131
+
132
+ ```json
133
+ { "tasks": [{ "id": "nightly", "agent": "main",
134
+ "schedule": "0 3 * * *", "prompt": "Check git status and test results, report anything broken" }] }
204
135
  ```
205
136
 
206
- ```markdown
137
+ </details>
138
+
139
+ <details>
140
+ <summary><b>Integrated terminal</b></summary>
141
+
142
+ Press `t` for an interactive shell inside the selected agent's workspace (xterm.js over WebSocket). The PTY comes from util-linux `script` when available, with a plain-pipe fallback — zero native dependencies.
143
+
144
+ </details>
145
+
146
+ <details>
147
+ <summary><b>File tree with previews &amp; editing</b></summary>
148
+
149
+ Browse the workspace from 🗂 files in the right panel: shiki syntax highlighting for code, rendered preview for Markdown, inline playback for images/video/audio, and in-place text editing that saves back to disk (409 on write conflicts).
150
+
151
+ </details>
152
+
153
+ <details>
154
+ <summary><b>Context management</b></summary>
155
+
156
+ Past a token budget (default: 75% of the model's window, or 96k if unknown), older turns are summarized by the LLM so work continues. Goals, memory and skills live in separate files, so context survives restarts and next-day resumes.
157
+
158
+ </details>
159
+
207
160
  ---
208
- name: release-checklist
209
- description: Steps to cut a release safely
161
+
162
+ ## ⚠️ Security (please read)
163
+
164
+ Agents can run `bash` and rewrite files — including `rm` and `npm install`.
165
+
166
+ - Designed to run under a **dedicated Linux user**
167
+ - `git commit` before handing over a repo you care about
168
+ - File operations outside the workspace are rejected (`safeJoin`)
169
+ - teapot listens on localhost only by default. If you expose it, set **both** `--host 0.0.0.0` and an API token (`TEAPOT_API_TOKEN` env or config `password`):
170
+
171
+ ```sh
172
+ TEAPOT_API_TOKEN=mysecret teapot --host 0.0.0.0 --port 7788
173
+ ```
174
+
210
175
  ---
211
176
 
212
- 1. run pnpm test
213
- 2. bump version ...
177
+ <a id="-reference"></a>
178
+ ## 📖 Reference
179
+
180
+ <details>
181
+ <summary><b>Config reference</b></summary>
182
+
183
+ | Key | Default | Meaning |
184
+ |---|---|---|
185
+ | `port` | 7788 | listen port (env `TEAPOT_PORT`, CLI `--port/-p`) |
186
+ | `host` | 127.0.0.1 | bind address (env `TEAPOT_HOST`, CLI `--host`; `0.0.0.0` exposes to LAN) |
187
+ | `dataDir` | `~/.local/share/teapot-coding-agent` | session logs etc. (env `TEAPOT_DATA_DIR`) |
188
+ | `providers.<name>` | — | `{ baseUrl, apiKey, model? }` OpenAI-compatible endpoint |
189
+ | `defaultProvider` | — | used when an agent doesn't specify one |
190
+ | `agents[].id` | required | URL key / display name |
191
+ | `agents[].workspace` | required | working directory |
192
+ | `agents[].provider` / `model` | inherited | per-agent overrides |
193
+ | `agents[].contextWindowTokens` | auto-inferred | model's real window (drives gauge + compaction) |
194
+ | `agents[].readOnly` | false | true blocks mutating tools |
195
+ | `agents[].autoContinue` | true | keep looping toward an active goal |
196
+ | `contextTokenBudget` | derived | compaction threshold in raw tokens; null/unset = 75% derivation (recommended) |
197
+ | `maxSpawnDepth` | 3 | sub-agent nesting limit |
198
+ | `password` | — | API auth (env `TEAPOT_API_TOKEN` wins) |
199
+ | `tasks[]` | — | cron tasks `{ id, agent, schedule, prompt }` |
200
+
201
+ Lookup order: CLI arg → `$TEAPOT_CONFIG` → `~/.config/teapot-coding-agent/config.json` → `./teapot.config.json`
202
+
203
+ </details>
204
+
205
+ <details>
206
+ <summary><b>Mixing providers</b></summary>
207
+
208
+ ```jsonc
209
+ {
210
+ "providers": {
211
+ "openrouter": { "baseUrl": "https://openrouter.ai/api/v1", "apiKey": "sk-or-..." },
212
+ "local": { "baseUrl": "http://localhost:8080/v1", "apiKey": "llama.cpp" }
213
+ },
214
+ "defaultProvider": "openrouter",
215
+ "agents": [
216
+ { "id": "coder", "workspace": "~/proj", "model": "anthropic/claude-sonnet-4" },
217
+ { "id": "reviewer", "workspace": "~/proj", "provider": "local" }
218
+ ]
219
+ }
214
220
  ```
215
221
 
216
- - The system prompt lists every discovered skill (name + description);
217
- workspace skills override same-named global ones.
218
- - The agent calls `load_skill(name)` when a task matches and follows it.
219
- - The agent calls `save_skill(name, description, content, files?)` to distill a
220
- reusable procedure — `files` bundles helper scripts next to `SKILL.md`
221
- (made executable automatically), and `load_skill` lists them as runnable
222
- workspace paths. Available from the next turn, forever.
223
- - Bundled skill: [`skills/qa-adversarial`](skills/qa-adversarial/SKILL.md) —
224
- seven adversarial QA personas. Copy it into
225
- `~/.config/teapot-coding-agent/skills/` (global) or a workspace's
226
- `skills/` folder to enable it.
222
+ Anything OpenAI-compatible works: OpenRouter / OpenAI / Ollama / vLLM / llama.cpp.
223
+ Requests to openrouter.ai automatically carry app-attribution headers.
227
224
 
228
- ### Session log format (JSONL)
225
+ Model context windows are inferred from `/v1/models` at startup and drive the runtime gauge plus the derived compaction budget (manual override supported).
229
226
 
230
- One file per session (`<dataDir>/sessions/<sid>/chat.jsonl`, sid =
231
- `<agentId>-<uuid8>`); every conversation *including forks* lives in the same
232
- interleaved stream:
227
+ </details>
233
228
 
234
- ```json
235
- {"v":1,"id":"e27","seq":27,"ts":"…","agent":"alpha","session":"alpha-9f3c21ab",
236
- "branch":"br032sl","parent":"e26","type":"fork",
237
- "data":{"fromSession":"alpha-9f3c21ab","fromBranch":"br0","fromEvent":"e26","newBranch":"br032sl"}}
229
+ <details>
230
+ <summary><b>HTTP API</b></summary>
231
+
232
+ ```
233
+ GET /api/agents list
234
+ POST /api/agents create { workspace, id?, provider?, model?, start? }
235
+ GET /api/agents/:id/events?limit=300 events ( ?before=<id> pages upward )
236
+ GET /api/agents/:id/branches branch list
237
+ GET /api/agents/:id/file?path= fetch text file
238
+ PUT /api/agents/:id/file?path= save { content, baseContent? } (409 on conflict)
239
+ GET /api/agents/:id/raw?path= raw media bytes
240
+ GET /api/agents/:id/tree file tree
241
+ POST /api/agents/:id/prompt send { text, start? } → { promptId }
242
+ POST /api/agents/:id/prompt/cancel withdraw { promptId } (409 once delivered)
243
+ POST /api/agents/:id/goal { text?, status?, verify? }
244
+ POST /api/agents/:id/start|stop|fork|load
245
+ DELETE /api/agents/:id remove (logs kept)
246
+ GET /api/metrics RSS / heap / loadavg
247
+ WS /api/ws live event stream
238
248
  ```
239
249
 
240
- - every event carries `session`, `branch`, `parent` (previous event on the same branch), monotonic `seq`
241
- - a `fork` event records exactly where the new branch split off
242
- - reconstruct any conversation: filter `branch === X` (or walk `parent` links
243
- backwards across the fork point)
244
- - event types: `session_start, fork, prompt, system_note, message, tool_call,
245
- tool_result, state, progress, error, usage, goal`
246
- - torn trailing lines are ignored on read → crash-safe append-only log
250
+ All API routes honor optional bearer auth.
247
251
 
248
- ### Progress reports
252
+ </details>
249
253
 
250
- Two complementary mechanisms:
254
+ <details>
255
+ <summary><b>Session log (JSONL) format</b></summary>
251
256
 
252
- 1. the agent can call `report_progress` whenever it wants;
253
- 2. the harness injects a progress-report request at the next *turn boundary*
254
- after `progressIntervalMs` of activity — never mid-turn, so it never
255
- interrupts a tool call. Reports are first-class `progress` events.
257
+ Append-only JSONL you can read with `cat`/`jq`:
256
258
 
257
- ### Scheduled tasks
259
+ ```jsonl
260
+ {"v":1,"id":"e1","type":"prompt","data":{"source":"user","text":"..."}}
261
+ {"v":1,"id":"e2","type":"tool_call","data":{"callId":"…","name":"bash","argsRaw":"…"}}
262
+ {"v":1,"id":"e3","type":"tool_result","data":{"callId":"…","ok":true,"durationMs":117}}
263
+ {"v":1,"id":"e4","type":"message","data":{"role":"assistant","content":"…"}}
264
+ ```
258
265
 
259
- Cron-style specs (`*/10 * * * *` or `every 10m`) checked by the single 15 s
260
- master tick. Tasks run as prompts on **forked branches** by default so periodic
261
- chatter never disturbs an agent's main line of work.
266
+ Each event links to its parent, forks share the branch point, and `goal.md` / `memory.md` / `todo.md` live beside `chat.jsonl` under `sessions/<agent>-<uuid>/`.
262
267
 
263
- ## HTTP API
268
+ </details>
264
269
 
265
- ```
266
- GET /api/agents list snapshots
267
- GET /api/agents/:id one snapshot
268
- POST /api/agents/:id/prompt {text, start?}
269
- POST /api/agents/:id/start | /stop
270
- POST /api/agents/:id/load lazy session restore (stopped → idle)
271
- POST /api/agents/:id/goal {text, notify?} or {status}
272
- POST /api/agents/:id/fork {} → new branch, same session log
273
- POST /api/agents/:id/edit-prompt {eventId, text, tail: "discard"|"summarize"} → fork & resend
274
- GET /api/agents/:id/events?limit&branch&session
275
- GET /api/agents/:id/branches
276
- GET /api/tasks scheduled tasks with computed next-fire times
277
- GET /api/metrics master rss/heap/load + per-agent stats
278
- GET /api/events SSE updates (push, no polling)
279
- GET /brew 418 I'm a teapot (RFC 2324)
270
+ <details>
271
+ <summary><b>Development (from a checkout)</b></summary>
272
+
273
+ ```sh
274
+ pnpm install
275
+ pnpm dev # run TypeScript natively
276
+ pnpm dev-web # Vite HMR (separate terminal)
277
+ pnpm test # node --test
278
+ pnpm build # tsc + vite build → dist/ + public/
280
279
  ```
281
280
 
282
- ## Security / execution model
281
+ Layout: `src/master.ts` (boot/cron/config) · `src/agent/` (loop/tools) ·
282
+ `src/server/api.ts` (Hono REST+WS) · `frontend/` (SolidJS) · `test/` (node:test)
283
283
 
284
- Designed for a dedicated agent Linux user; workspaces are path-confined,
285
- subprocesses run in killable process groups with hard timeouts, and resource
286
- limits (RLIMIT_* / cgroups) have a natural insertion point in
287
- `src/agent/tools.ts:runShell`.
284
+ </details>
288
285
 
289
- **LAN exposure**: the API has no auth by default (localhost-first tool). To
290
- expose it beyond localhost, set `TEAPOT_API_TOKEN=<secret>` (env wins) or a
291
- `password` field in the config — every `/api/*`
292
- route then requires `Authorization: Bearer <secret>` (WebSocket handshakes
293
- accept `?token=<secret>`). In the web UI, open
294
- `http://host:7788/#token=<secret>` once; the token is stored locally and
295
- attached automatically. The master survives agent crashes by
296
- construction: agent errors never escape their own loop, and global handlers
297
- keep the process alive.
286
+ ---
298
287
 
299
288
  ## License
300
289
 
301
- AGPL-3.0-or-later
290
+ AGPL-3.0-or-later — [LICENSE](LICENSE)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "teapot-coding-agent",
3
- "version": "0.15.6",
3
+ "version": "0.15.8",
4
4
  "description": "A lightweight, always-on multi-agent harness for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-or-later",