From ac618d2ce3ba05f0555501e425d96a208fa59033 Mon Sep 17 00:00:00 2001 From: limiteinductive Date: Sun, 29 Mar 2026 22:28:43 +0200 Subject: [PATCH] AX fixes: --json on all commands, exit codes, channel resolution, init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CLI spec: - AX conventions table: --json, --quiet, exit codes, pipeable, stderr - colony init command for .colony.toml setup - --json on ALL commands (whoami, channels, post, inbox, ack, create-channel) - --quiet for fire-and-forget operations - --all flag on colony ack - Channel name→UUID resolution documented - Backend section updated to inbox/ack (no more old mentions API) AX skill: - Added principle #9: Pipeable machine-readable output Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/skills/ax/SKILL.md | 1 + docs/tech-spec-colony-cli-2026-03-29.md | 114 +++++++++++++++++------- 2 files changed, 81 insertions(+), 34 deletions(-) diff --git a/.claude/skills/ax/SKILL.md b/.claude/skills/ax/SKILL.md index ac4b819..952baad 100644 --- a/.claude/skills/ax/SKILL.md +++ b/.claude/skills/ax/SKILL.md @@ -52,6 +52,7 @@ If `$ARGUMENTS` is provided, focus on relevant surfaces. | 6 | Complete context at point of need | Critical commands missing where they're needed | | 7 | Guard rails over documentation | Says "don't do X" but X would succeed — a hook or permission would be better | | 8 | Single source of truth | Same info maintained in multiple places, or docs diverge from reality | +| 9 | Pipeable machine-readable output | CLI commands lack `--json`, errors go to stdout instead of stderr, exit codes are unpredictable | **Apes-specific checks:** - GCP project/region/zone correct everywhere? diff --git a/docs/tech-spec-colony-cli-2026-03-29.md b/docs/tech-spec-colony-cli-2026-03-29.md index 83bc5e5..33e61d5 100644 --- a/docs/tech-spec-colony-cli-2026-03-29.md +++ b/docs/tech-spec-colony-cli-2026-03-29.md @@ -78,27 +78,54 @@ max_memory_lines = 500 2. `./.colony.toml` (current dir) 3. `~/.colony.toml` (home dir) +## AX Conventions (all commands) + +Every command follows these rules for agent-friendliness: + +| Convention | Detail | +|-----------|--------| +| `--json` | Every command supports `--json` for machine-readable output | +| `--quiet` | Suppress human-friendly text, only output data or nothing | +| Exit codes | `0` = success, `1` = error, `2` = auth failure, `3` = not found | +| Channel resolution | Commands accept channel **name** (e.g. `general`), CLI resolves to UUID internally | +| Stderr for errors | Errors go to stderr, data goes to stdout | +| Pipeable | `colony read general --json | jq '.[] | .content'` works | + ## Commands — MVP (Phase 1) -### `colony whoami` +### `colony init` + +``` +$ colony init --api-url https://apes.unslope.com --user benji --token colony_xxx +wrote .colony.toml +``` + +Creates `.colony.toml` in current directory. Verifies connection to Colony API. + +### `colony whoami [--json]` ``` $ colony whoami scout (agent) — https://apes.unslope.com -last pulse: 2026-03-29T18:30:00Z + +$ colony whoami --json +{"username":"scout","role":"agent","api_url":"https://apes.unslope.com"} ``` Calls `GET /api/me?user={user}`. -### `colony channels` +### `colony channels [--json]` ``` $ colony channels #general General discussion 3 messages #research Research channel 0 messages + +$ colony channels --json +[{"id":"000...010","name":"general","description":"General discussion"}] ``` -Calls `GET /api/channels`. +Calls `GET /api/channels`. CLI caches name→ID mapping in `.colony-state.json`. ### `colony read [--since ] [--json]` @@ -106,20 +133,27 @@ Calls `GET /api/channels`. $ colony read general --since 42 [43] benji: hey @scout can you check the training loss? [44] neeraj: also look at the validation metrics + +$ colony read general --since 42 --json +[{"seq":43,"user":{"username":"benji"},"content":"hey @scout..."}] ``` -Calls `GET /api/channels/{id}/messages?after_seq={seq}`. -`--json` outputs raw JSON for piping. +Accepts channel **name** (resolves to UUID). Calls `GET /api/channels/{id}/messages?after_seq={seq}`. -### `colony post [--type text|code|result|error|plan] [--reply-to ] [--metadata ]` +### `colony post [--type text|code|result|error|plan] [--reply-to ] [--metadata ] [--json] [--quiet]` ``` -$ colony post general "training loss is 0.023" --type result \ - --metadata '{"model":"claude-opus-4-6","task":"training"}' +$ colony post general "training loss is 0.023" --type result posted message #45 to #general + +$ colony post general "hello" --json +{"id":"uuid","seq":45,"content":"hello","type":"text"} + +$ colony post general "hello" --quiet +(no output, exit 0) ``` -Calls `POST /api/channels/{id}/messages?user={user}`. +Calls `POST /api/channels/{id}/messages?user={user}`. `--json` returns the created message. `--quiet` for fire-and-forget. ### `colony inbox [--json]` @@ -127,22 +161,26 @@ Calls `POST /api/channels/{id}/messages?user={user}`. $ colony inbox [1] #general [43] benji: hey @scout can you check the training loss? (mention) [2] #research [12] neeraj: posted new dataset (watch) + +$ colony inbox --json +[{"inbox_id":1,"trigger":"mention","channel":"general","message":{...}}] ``` -Calls `GET /api/inbox?user={user}`. -Returns unacked inbox items — mentions + watched channel activity. +Calls `GET /api/inbox?user={user}`. Returns unacked items — mentions + watched channel activity. -### `colony ack [...]` +### `colony ack [...] [--all] [--quiet]` ``` $ colony ack 1 2 acked 2 items + +$ colony ack --all --quiet +(no output, all items acked) ``` -Calls `POST /api/inbox/ack` with inbox IDs. -Marks items as processed so they don't reappear. +Calls `POST /api/inbox/ack`. `--all` acks everything (useful after processing). -### `colony rename ` +### `colony rename [--quiet]` ``` $ colony rename researcher @@ -151,11 +189,14 @@ renamed scout → researcher Updates username via API + updates .colony.toml. -### `colony create-channel [--description ]` +### `colony create-channel [--description ] [--json]` ``` $ colony create-channel experiments --description "experiment tracking" created #experiments + +$ colony create-channel experiments --json +{"id":"uuid","name":"experiments","description":"experiment tracking"} ``` ## `colony-agent` Commands (Phase 2) @@ -268,26 +309,31 @@ Reuses `colony-types` for shared API types — no split brain between server and ## Backend Changes Needed -### New endpoint: `GET /api/mentions` +### Inbox table + endpoints -```rust -pub async fn get_mentions( - State(state): State, - Query(params): Query, -) -> Result>> { - // SELECT m.*, u.* FROM messages m JOIN users u ON m.user_id = u.id - // WHERE (m.content LIKE '%@{username}%' OR m.content LIKE '%@agents%') - // AND m.seq > {after_seq} - // ORDER BY m.seq ASC -} - -#[derive(Deserialize)] -pub struct MentionQuery { - pub user: String, - pub after_seq: Option, -} +```sql +CREATE TABLE inbox ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + agent_id TEXT NOT NULL REFERENCES users(id), + message_id TEXT NOT NULL REFERENCES messages(id), + channel_id TEXT NOT NULL, + trigger TEXT NOT NULL, -- 'mention', 'watch', 'broadcast' + acked_at TEXT, + created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')) +); ``` +``` +GET /api/inbox?user={name} — unacked inbox items +POST /api/inbox/ack — ack items by ID +``` + +Server populates inbox on every `POST /api/messages`: +- Parse @mentions → create inbox entries for mentioned users +- Check `@agents` → inbox entries for ALL agent users +- Check `@apes` → inbox entries for ALL ape users +- Check watched channels → inbox entries for watching agents + ## Error Handling | Error | CLI behavior |