teapot-coding-agent 0.15.6 → 0.15.7

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,294 @@
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. Write a config file
55
22
 
56
23
  ```sh
57
- pnpm install
58
24
  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
25
+ nano ~/.config/teapot-coding-agent/config.json
62
26
  ```
63
27
 
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`.
28
+ **Minimal setup** (OpenRouter — other providers below):
69
29
 
70
- ## Multiple providers
71
-
72
- Agents are matched to named OpenAI-compatible providers:
73
-
74
- ```jsonc
30
+ ```json
75
31
  {
76
32
  "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" }
33
+ "openrouter": {
34
+ "baseUrl": "https://openrouter.ai/api/v1",
35
+ "apiKey": "sk-or-your-key",
36
+ "model": "anthropic/claude-sonnet-4"
37
+ }
80
38
  },
81
39
  "defaultProvider": "openrouter",
82
40
  "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
41
+ { "id": "main", "workspace": "/home/you/my-project" }
87
42
  ]
88
43
  }
89
44
  ```
90
45
 
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.
46
+ Prefer copying a template? Grab [`teapot.config.example.json`](teapot.config.example.json).
94
47
 
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.
100
-
101
- ## Architecture
48
+ ### 3. Run
102
49
 
50
+ ```sh
51
+ teapot
103
52
  ```
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
53
+
54
+ → Open **http://localhost:7788**. That's it.
55
+
56
+ ### 4. Use it
57
+
58
+ - Click `#main` in the left panel
59
+ - Type an instruction in the composer (e.g. "Fix this bug and make the tests pass")
60
+ - The agent reads/writes files, runs bash, and works on its own
61
+
62
+ | Action | How |
63
+ |---|---|
64
+ | Terminal | `t` |
65
+ | Right panel (goal/progress/runtime) | `d` |
66
+ | Command list | type `/` in the composer |
67
+ | Interrupt the agent | `Esc` |
68
+
69
+ ---
70
+
71
+ ## 🤔 What is this?
72
+
73
+ One line: **a server that hosts several autonomous coding agents over any OpenAI-compatible API, operated from a browser.**
74
+
75
+ ```text
76
+ ├─ agent: android ── ~/projects/android-app
77
+ ├─ agent: kernel ── ~/projects/kernel
78
+ └─ agent: web ── ~/projects/film-sims-web
108
79
  ```
109
80
 
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:
81
+ 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).
82
+
83
+ ### When would I use it?
84
+
85
+ - Long-running self-directed tasks like *"triage every bug in this repo and fix them until tests pass"*
86
+ - **Different models per project** — heavy work on Sonnet, code review on a local Qwen
87
+ - Watch progress, goals and task lists in the browser while you do something else
88
+
89
+ ### How does it compare to CLI tools?
90
+
91
+ | | teapot | Claude Code & similar CLIs |
92
+ |---|---|---|
93
+ | Form | resident server + web UI | interactive terminal |
94
+ | Multiple agents | ✅ parallel | usually one session |
95
+ | Mixed models | ✅ per agent | fixed |
96
+ | Long-running work | ✅ auto-restores from JSONL logs | manual session juggling |
97
+ | Scheduled tasks (cron) | ✅ 15-second tick | ❌ |
200
98
 
99
+ ---
100
+
101
+ ## 🔧 Features
102
+
103
+ <details>
104
+ <summary><b>Goals &amp; autonomous loop</b></summary>
105
+
106
+ 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:
107
+
108
+ ```text
109
+ goal: "Add account deletion to the auth module"
110
+ verify: "npm test passes with zero failures / README documents the endpoint"
111
+ ↓ on finish
112
+ independent audit → approved ⇒ done · changes-required ⇒ gaps queued back to the worker
201
113
  ```
202
- <workspace>/skills/<name>/SKILL.md # project skills (git-friendly)
203
- ~/.config/teapot-coding-agent/skills/<name>/SKILL.md # shared across agents
114
+
115
+ </details>
116
+
117
+ <details>
118
+ <summary><b>Sub-agents</b></summary>
119
+
120
+ 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).
121
+
122
+ </details>
123
+
124
+ <details>
125
+ <summary><b>Memory / task list / skills</b></summary>
126
+
127
+ - **memory.md** — durable notes per session (set_memory / get_memory)
128
+ - **todo.md** — checklist shared with the operator; supports surgical per-item updates
129
+ - **skills** — reusable playbooks stored globally (`~/.config/teapot-coding-agent/skills/`) or per workspace; workspace versions shadow global ones
130
+
131
+ </details>
132
+
133
+ <details>
134
+ <summary><b>Scheduled tasks (cron)</b></summary>
135
+
136
+ ```json
137
+ { "tasks": [{ "id": "nightly", "agent": "main",
138
+ "schedule": "0 3 * * *", "prompt": "Check git status and test results, report anything broken" }] }
204
139
  ```
205
140
 
206
- ```markdown
141
+ </details>
142
+
143
+ <details>
144
+ <summary><b>Integrated terminal</b></summary>
145
+
146
+ 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.
147
+
148
+ </details>
149
+
150
+ <details>
151
+ <summary><b>File tree with previews &amp; editing</b></summary>
152
+
153
+ 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).
154
+
155
+ </details>
156
+
157
+ <details>
158
+ <summary><b>Context management</b></summary>
159
+
160
+ 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.
161
+
162
+ </details>
163
+
207
164
  ---
208
- name: release-checklist
209
- description: Steps to cut a release safely
165
+
166
+ ## ⚠️ Security (please read)
167
+
168
+ Agents can run `bash` and rewrite files — including `rm` and `npm install`.
169
+
170
+ - Designed to run under a **dedicated Linux user**
171
+ - `git commit` before handing over a repo you care about
172
+ - File operations outside the workspace are rejected (`safeJoin`)
173
+ - 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`):
174
+
175
+ ```sh
176
+ TEAPOT_API_TOKEN=mysecret teapot --host 0.0.0.0 --port 7788
177
+ ```
178
+
210
179
  ---
211
180
 
212
- 1. run pnpm test
213
- 2. bump version ...
181
+ <a id="-reference"></a>
182
+ ## 📖 Reference
183
+
184
+ <details>
185
+ <summary><b>Config reference</b></summary>
186
+
187
+ | Key | Default | Meaning |
188
+ |---|---|---|
189
+ | `port` | 7788 | listen port (env `TEAPOT_PORT`, CLI `--port/-p`) |
190
+ | `host` | 127.0.0.1 | bind address (env `TEAPOT_HOST`, CLI `--host`; `0.0.0.0` exposes to LAN) |
191
+ | `dataDir` | `~/.local/share/teapot-coding-agent` | session logs etc. (env `TEAPOT_DATA_DIR`) |
192
+ | `providers.<name>` | — | `{ baseUrl, apiKey, model? }` OpenAI-compatible endpoint |
193
+ | `defaultProvider` | — | used when an agent doesn't specify one |
194
+ | `agents[].id` | required | URL key / display name |
195
+ | `agents[].workspace` | required | working directory |
196
+ | `agents[].provider` / `model` | inherited | per-agent overrides |
197
+ | `agents[].contextWindowTokens` | auto-inferred | model's real window (drives gauge + compaction) |
198
+ | `agents[].readOnly` | false | true blocks mutating tools |
199
+ | `agents[].autoContinue` | true | keep looping toward an active goal |
200
+ | `contextTokenBudget` | derived | compaction threshold in raw tokens; null/unset = 75% derivation (recommended) |
201
+ | `maxSpawnDepth` | 3 | sub-agent nesting limit |
202
+ | `password` | — | API auth (env `TEAPOT_API_TOKEN` wins) |
203
+ | `tasks[]` | — | cron tasks `{ id, agent, schedule, prompt }` |
204
+
205
+ Lookup order: CLI arg → `$TEAPOT_CONFIG` → `~/.config/teapot-coding-agent/config.json` → `./teapot.config.json`
206
+
207
+ </details>
208
+
209
+ <details>
210
+ <summary><b>Mixing providers</b></summary>
211
+
212
+ ```jsonc
213
+ {
214
+ "providers": {
215
+ "openrouter": { "baseUrl": "https://openrouter.ai/api/v1", "apiKey": "sk-or-..." },
216
+ "local": { "baseUrl": "http://localhost:8080/v1", "apiKey": "llama.cpp" }
217
+ },
218
+ "defaultProvider": "openrouter",
219
+ "agents": [
220
+ { "id": "coder", "workspace": "~/proj", "model": "anthropic/claude-sonnet-4" },
221
+ { "id": "reviewer", "workspace": "~/proj", "provider": "local" }
222
+ ]
223
+ }
214
224
  ```
215
225
 
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.
226
+ Anything OpenAI-compatible works: OpenRouter / OpenAI / Ollama / vLLM / llama.cpp.
227
+ Requests to openrouter.ai automatically carry app-attribution headers.
227
228
 
228
- ### Session log format (JSONL)
229
+ Model context windows are inferred from `/v1/models` at startup and drive the runtime gauge plus the derived compaction budget (manual override supported).
229
230
 
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:
231
+ </details>
232
+
233
+ <details>
234
+ <summary><b>HTTP API</b></summary>
233
235
 
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"}}
238
236
  ```
237
+ GET /api/agents list
238
+ POST /api/agents create { workspace, id?, provider?, model?, start? }
239
+ GET /api/agents/:id/events?limit=300 events ( ?before=<id> pages upward )
240
+ GET /api/agents/:id/branches branch list
241
+ GET /api/agents/:id/file?path= fetch text file
242
+ PUT /api/agents/:id/file?path= save { content, baseContent? } (409 on conflict)
243
+ GET /api/agents/:id/raw?path= raw media bytes
244
+ GET /api/agents/:id/tree file tree
245
+ POST /api/agents/:id/prompt send { text, start? } → { promptId }
246
+ POST /api/agents/:id/prompt/cancel withdraw { promptId } (409 once delivered)
247
+ POST /api/agents/:id/goal { text?, status?, verify? }
248
+ POST /api/agents/:id/start|stop|fork|load
249
+ DELETE /api/agents/:id remove (logs kept)
250
+ GET /api/metrics RSS / heap / loadavg
251
+ WS /api/ws live event stream
252
+ ```
253
+
254
+ All API routes honor optional bearer auth.
239
255
 
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
256
+ </details>
247
257
 
248
- ### Progress reports
258
+ <details>
259
+ <summary><b>Session log (JSONL) format</b></summary>
249
260
 
250
- Two complementary mechanisms:
261
+ Append-only JSONL you can read with `cat`/`jq`:
251
262
 
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.
263
+ ```jsonl
264
+ {"v":1,"id":"e1","type":"prompt","data":{"source":"user","text":"..."}}
265
+ {"v":1,"id":"e2","type":"tool_call","data":{"callId":"…","name":"bash","argsRaw":"…"}}
266
+ {"v":1,"id":"e3","type":"tool_result","data":{"callId":"…","ok":true,"durationMs":117}}
267
+ {"v":1,"id":"e4","type":"message","data":{"role":"assistant","content":"…"}}
268
+ ```
256
269
 
257
- ### Scheduled tasks
270
+ 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>/`.
258
271
 
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.
272
+ </details>
262
273
 
263
- ## HTTP API
274
+ <details>
275
+ <summary><b>Development (from a checkout)</b></summary>
264
276
 
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)
277
+ ```sh
278
+ pnpm install
279
+ pnpm dev # run TypeScript natively
280
+ pnpm dev-web # Vite HMR (separate terminal)
281
+ pnpm test # node --test
282
+ pnpm build # tsc + vite build → dist/ + public/
280
283
  ```
281
284
 
282
- ## Security / execution model
285
+ Layout: `src/master.ts` (boot/cron/config) · `src/agent/` (loop/tools) ·
286
+ `src/server/api.ts` (Hono REST+WS) · `frontend/` (SolidJS) · `test/` (node:test)
283
287
 
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`.
288
+ </details>
288
289
 
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.
290
+ ---
298
291
 
299
292
  ## License
300
293
 
301
- AGPL-3.0-or-later
294
+ 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.7",
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",