From e160ebaf9105216a2552ee72431795fdb9775e62 Mon Sep 17 00:00:00 2001 From: Owain Lewis Date: Wed, 29 Jul 2026 14:50:59 +0100 Subject: [PATCH 1/2] docs: add agent contributor guide --- AGENTS.md | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..58b5e77 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,186 @@ +# AGENTS.md + +This guide is for coding agents working on Push. For general contributor setup, +pull request expectations, and the documentation workflow, read +[CONTRIBUTING.md](CONTRIBUTING.md) and +[docs/contributing.md](docs/contributing.md). + +## Product boundary + +Push is one small local Rust process. It connects private iMessage, Telegram, +and Slack conversations to Claude Code, Codex, or Pi, and runs scheduled +Markdown jobs. + +Keep ownership clear: + +- Push owns channels, allowlists, routing, scheduling, durable history, + session state, crash recovery, and delivery. +- The assistant repository owns `SOUL.md`, context, jobs, and optional project + skills. +- The selected agent owns reasoning, tools, skills, MCP, authentication, + models, and interactive permissions. + +Do not add an agent loop, plugin system, MCP layer, or tool runner to Push. +Extend the existing channel or backend boundaries instead. + +Read [docs/architecture.md](docs/architecture.md) before changing state, +sessions, queues, cursors, crash recovery, scheduling, shutdown, or delivery. + +## Code map + +| Area | Location | +| --- | --- | +| CLI and startup | `src/main.rs` | +| Config loading, migration, and validation | `src/config.rs` | +| Channel-neutral contract | `src/channel.rs` | +| iMessage adapter | `src/imessage/` | +| Telegram adapter | `src/telegram.rs` | +| Slack adapter and durable inbox | `src/slack.rs` | +| Gateway loops and per-thread queues | `src/gateway/` | +| Agent boundary | `src/agent.rs` | +| Claude Code, Codex, and Pi adapters | `src/claude.rs`, `src/codex.rs`, `src/pi.rs` | +| Canonical SQLite history | `src/history.rs` | +| JSON cursor and session state | `src/store.rs` | +| Jobs, scheduler, locks, and run ledger | `src/jobs.rs` | +| Assistant repository setup | `src/assistant.rs`, `src/soul.rs` | +| Diagnostics and audit | `src/doctor.rs`, `src/audit.rs` | +| Voice processing | `src/voice.rs` | +| Gateway integration tests | `src/gateway/tests.rs` | +| CLI, docs, installer, and crash tests | `tests/` | + +## Development + +Use the stable Rust toolchain. Build and test with the lockfile: + +```sh +cargo build --locked +cargo test --locked +``` + +Before every pull request, run the same core checks as CI: + +```sh +cargo fmt --all --check +cargo clippy --locked --all-targets -- -D warnings +cargo build --locked +cargo test --locked +``` + +Run focused tests while iterating, then run the full gate. CI runs the Rust +gate on Linux and macOS. It also runs `tests/install.sh`, +`tests/release-version.sh`, and `mkdocs build --strict`. + +For documentation-only changes, at minimum run: + +```sh +cargo test --locked --test docs +mkdocs build --strict +``` + +The docs command needs the packages in `requirements-docs.txt`. + +## Architecture rules + +### Channels + +- `ChannelContract` is the provider boundary. Add a concrete implementation + and a `Channel` variant for a new built-in channel. +- Keep provider details such as addressing, allowlists, message splitting, + rich formatting, retry timing, typing, and voice transport in the adapter. +- Do not add channel-name branches to shared polling, routing, worker, + delivery, or shutdown code. +- Accepted messages must produce a stable channel-qualified thread key and an + exact reply target. Never let replies or sessions cross channels. +- Poll and send futures must be safe to drop during shutdown. Typing updates + are best effort and must not fail an assistant turn. + +### Durable processing + +- Record accepted inbound content before backend dispatch. +- Persist generated outbound content before delivery. Retries must resend the + stored result without rerunning the backend. +- A chat backend run may repeat if the process crashes after execution but + before recording its outbound result. Only an existing outbound row prevents + rerunning that turn. +- Do not advance a channel cursor past an earlier in-flight row. +- Checkpoint chunk delivery monotonically and resume at the first unsent chunk. +- Preserve existing `state.json` compatibility fields and SQLite data. When + changing the history schema, add a migration, advance the schema version, + and test upgrade behavior. +- Keep work for each thread ordered while allowing independent threads and + channels to make progress. + +### Agent backends + +- Keep the shared request and result shape in `src/agent.rs`. Backend-specific + CLI flags and JSON parsing belong in the matching adapter. +- Chat runs preserve the selected agent's permission configuration. Scheduled + jobs are unattended and cannot depend on interactive approval. +- Keep system instructions separate from user prompt content. +- A missing stored backend session may rotate once and rehydrate from bounded + canonical history. Do not create unbounded prompts or retry loops. +- Use the fake runner and contract tests. Unit tests must not invoke installed + agent binaries. + +### Jobs and recovery + +- Validate job Markdown before execution and keep the run ledger authoritative. +- Scheduled work must remain bounded by worker and timeout limits. +- Preserve the rule that a result is committed before notification. Restart + recovery may resume queued work or delivery, but must not rerun backend work + already recorded as started. +- Keep scheduled delivery separate from ordinary reply delivery when their + ledgers or retry rules differ. + +### Security + +- Push uses outbound connections only. Do not introduce a listening server or + webhook without an explicit architecture decision. +- Apply channel type checks and allowlists before backend dispatch or voice + download. +- Never commit or expose tokens, personal config, message content, assistant + identity, audit logs, databases, cursor state, or backend session IDs. + Normal logs must redact content. Audit content is allowed only through the + explicit `audit_log_content` opt-in and remains sensitive. +- Runtime state and secrets must stay outside the Git-versioned assistant + repository. Preserve path canonicalization, symlink checks, and owner-only + permissions. +- Treat every allowlisted sender as an operator of the configured agent. + +## Testing rules + +- For a bug, add a regression test that fails for the original cause when + practical. +- Cover failure and restart paths for changes to persistence, cursors, + sessions, queues, or delivery. +- Use fakes and local test servers for agent and provider behavior. Tests must + not need real chat databases, API credentials, network services, or an + installed agent. +- Keep platform behavior explicit. iMessage production access is macOS-only; + Telegram and Slack must remain usable on Linux. +- If public behavior, configuration, or CLI output changes, update the + canonical page under `docs/` and any focused CLI or config tests. + +## Documentation and releases + +- `docs/` is the source for the website. Do not edit generated `site/` files. +- Keep each fact on one canonical docs page and link to it elsewhere. The + README is a product overview, not a second configuration reference. +- `Cargo.toml` is the source of the binary version. Release changes must refresh + `Cargo.lock` and keep the release tag check in `tests/release-version.sh` + consistent. + +## Common gotchas + +1. First startup skips existing channel backlog. Tests for startup and cursor + changes must cover both the initial and resumed cases. +2. Slack acknowledges accepted Socket Mode events only after its local inbox + persists them. Keep provider event IDs as the deduplication key. +3. A delivery error after a provider accepts a send can be ambiguous. Do not + claim exactly-once external delivery. +4. Changing a backend for a thread starts a fresh backend session with bounded + history. Never resume a session created by another backend. +5. Live iMessage checks require Full Disk Access for the exact terminal or + service process. Automated tests should use the existing fakes instead. +6. Configuration supports documented legacy migrations. Do not silently + reinterpret removed keys or weaken actionable validation errors. From 11dbe9459fa38330deb3e70d39b6485c7cd569a0 Mon Sep 17 00:00:00 2001 From: Owain Lewis Date: Wed, 29 Jul 2026 17:58:09 +0100 Subject: [PATCH 2/2] docs: simplify agent contributor guide --- AGENTS.md | 226 +++++++++++++++++------------------------------------- 1 file changed, 72 insertions(+), 154 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 58b5e77..e076571 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,63 +1,29 @@ # AGENTS.md -This guide is for coding agents working on Push. For general contributor setup, -pull request expectations, and the documentation workflow, read -[CONTRIBUTING.md](CONTRIBUTING.md) and -[docs/contributing.md](docs/contributing.md). +This guide contains project rules that are easy to miss from the code alone. +Use the contributor and architecture documentation for setup and deeper +context. ## Product boundary -Push is one small local Rust process. It connects private iMessage, Telegram, -and Slack conversations to Claude Code, Codex, or Pi, and runs scheduled -Markdown jobs. - -Keep ownership clear: +Push is a small messaging gateway, not an agent runtime. - Push owns channels, allowlists, routing, scheduling, durable history, - session state, crash recovery, and delivery. -- The assistant repository owns `SOUL.md`, context, jobs, and optional project - skills. -- The selected agent owns reasoning, tools, skills, MCP, authentication, - models, and interactive permissions. - -Do not add an agent loop, plugin system, MCP layer, or tool runner to Push. -Extend the existing channel or backend boundaries instead. - -Read [docs/architecture.md](docs/architecture.md) before changing state, -sessions, queues, cursors, crash recovery, scheduling, shutdown, or delivery. - -## Code map - -| Area | Location | -| --- | --- | -| CLI and startup | `src/main.rs` | -| Config loading, migration, and validation | `src/config.rs` | -| Channel-neutral contract | `src/channel.rs` | -| iMessage adapter | `src/imessage/` | -| Telegram adapter | `src/telegram.rs` | -| Slack adapter and durable inbox | `src/slack.rs` | -| Gateway loops and per-thread queues | `src/gateway/` | -| Agent boundary | `src/agent.rs` | -| Claude Code, Codex, and Pi adapters | `src/claude.rs`, `src/codex.rs`, `src/pi.rs` | -| Canonical SQLite history | `src/history.rs` | -| JSON cursor and session state | `src/store.rs` | -| Jobs, scheduler, locks, and run ledger | `src/jobs.rs` | -| Assistant repository setup | `src/assistant.rs`, `src/soul.rs` | -| Diagnostics and audit | `src/doctor.rs`, `src/audit.rs` | -| Voice processing | `src/voice.rs` | -| Gateway integration tests | `src/gateway/tests.rs` | -| CLI, docs, installer, and crash tests | `tests/` | - -## Development - -Use the stable Rust toolchain. Build and test with the lockfile: + sessions, recovery, and delivery. +- The assistant repository owns identity, context, jobs, and project skills. +- The selected backend owns reasoning, tools, skills, models, authentication, + and interactive permissions. -```sh -cargo build --locked -cargo test --locked -``` +Do not add an agent loop, plugin system, MCP layer, or tool runner. Extend the +existing channel or backend abstractions. + +Read the architecture documentation before changing state, sessions, queues, +cursors, recovery, scheduling, shutdown, or delivery. + +## Required checks -Before every pull request, run the same core checks as CI: +Use the stable Rust toolchain and the lockfile. Run focused tests while +iterating, then run the full gate before every pull request: ```sh cargo fmt --all --check @@ -66,121 +32,73 @@ cargo build --locked cargo test --locked ``` -Run focused tests while iterating, then run the full gate. CI runs the Rust -gate on Linux and macOS. It also runs `tests/install.sh`, -`tests/release-version.sh`, and `mkdocs build --strict`. - -For documentation-only changes, at minimum run: - -```sh -cargo test --locked --test docs -mkdocs build --strict -``` - -The docs command needs the packages in `requirements-docs.txt`. +Run the strict documentation build when documentation changes. Match any +additional platform or script checks selected by CI. ## Architecture rules ### Channels -- `ChannelContract` is the provider boundary. Add a concrete implementation - and a `Channel` variant for a new built-in channel. -- Keep provider details such as addressing, allowlists, message splitting, - rich formatting, retry timing, typing, and voice transport in the adapter. -- Do not add channel-name branches to shared polling, routing, worker, - delivery, or shutdown code. -- Accepted messages must produce a stable channel-qualified thread key and an - exact reply target. Never let replies or sessions cross channels. -- Poll and send futures must be safe to drop during shutdown. Typing updates - are best effort and must not fail an assistant turn. +- Keep provider-specific addressing, allowlists, formatting, retries, typing, + and voice transport inside the channel adapter. +- Do not add provider-name branches to shared polling, routing, worker, + delivery, or shutdown logic. +- Accepted messages must produce a stable channel-qualified thread key and the + exact reply target. Replies and sessions must never cross channels. +- Poll and send operations must be safe to cancel during shutdown. Typing is + best effort and must not fail a turn. ### Durable processing -- Record accepted inbound content before backend dispatch. -- Persist generated outbound content before delivery. Retries must resend the - stored result without rerunning the backend. -- A chat backend run may repeat if the process crashes after execution but - before recording its outbound result. Only an existing outbound row prevents - rerunning that turn. -- Do not advance a channel cursor past an earlier in-flight row. +- Record accepted input before backend dispatch. +- Persist generated output before delivery. Retry stored output without + rerunning the backend. +- A chat run may repeat after a crash if output was not yet recorded. Only a + recorded outbound result prevents rerunning that turn. +- Never advance a cursor past earlier in-flight work. - Checkpoint chunk delivery monotonically and resume at the first unsent chunk. -- Preserve existing `state.json` compatibility fields and SQLite data. When - changing the history schema, add a migration, advance the schema version, - and test upgrade behavior. -- Keep work for each thread ordered while allowing independent threads and - channels to make progress. - -### Agent backends - -- Keep the shared request and result shape in `src/agent.rs`. Backend-specific - CLI flags and JSON parsing belong in the matching adapter. -- Chat runs preserve the selected agent's permission configuration. Scheduled - jobs are unattended and cannot depend on interactive approval. -- Keep system instructions separate from user prompt content. -- A missing stored backend session may rotate once and rehydrate from bounded - canonical history. Do not create unbounded prompts or retry loops. -- Use the fake runner and contract tests. Unit tests must not invoke installed - agent binaries. +- Preserve persisted state and database compatibility. Add and test migrations + for schema changes. +- Keep each thread ordered while allowing independent threads and channels to + make progress. +- Do not claim exactly-once external delivery. A provider may accept a send + before returning an error. -### Jobs and recovery +### Agent backends and jobs -- Validate job Markdown before execution and keep the run ledger authoritative. -- Scheduled work must remain bounded by worker and timeout limits. -- Preserve the rule that a result is committed before notification. Restart - recovery may resume queued work or delivery, but must not rerun backend work - already recorded as started. -- Keep scheduled delivery separate from ordinary reply delivery when their - ledgers or retry rules differ. +- Keep backend-specific flags and output parsing inside the backend adapter. +- Keep system instructions separate from user prompt content. +- Chat runs preserve the backend's permission configuration. Unattended jobs + cannot depend on interactive approval. +- A missing backend session may rotate once and rehydrate from bounded history. + Do not introduce unbounded prompts or retry loops. +- Validate jobs before execution and keep the durable run ledger authoritative. +- Commit a job result before notification. Recovery may resume queued work or + delivery, but must not rerun backend work already recorded as started. ### Security -- Push uses outbound connections only. Do not introduce a listening server or - webhook without an explicit architecture decision. -- Apply channel type checks and allowlists before backend dispatch or voice +- Push uses outbound connections only. Adding a listener or webhook requires an + explicit architecture decision. +- Apply message-type checks and allowlists before backend dispatch or attachment download. -- Never commit or expose tokens, personal config, message content, assistant - identity, audit logs, databases, cursor state, or backend session IDs. - Normal logs must redact content. Audit content is allowed only through the - explicit `audit_log_content` opt-in and remains sensitive. -- Runtime state and secrets must stay outside the Git-versioned assistant - repository. Preserve path canonicalization, symlink checks, and owner-only - permissions. -- Treat every allowlisted sender as an operator of the configured agent. - -## Testing rules - -- For a bug, add a regression test that fails for the original cause when - practical. -- Cover failure and restart paths for changes to persistence, cursors, - sessions, queues, or delivery. -- Use fakes and local test servers for agent and provider behavior. Tests must - not need real chat databases, API credentials, network services, or an - installed agent. -- Keep platform behavior explicit. iMessage production access is macOS-only; - Telegram and Slack must remain usable on Linux. -- If public behavior, configuration, or CLI output changes, update the - canonical page under `docs/` and any focused CLI or config tests. - -## Documentation and releases - -- `docs/` is the source for the website. Do not edit generated `site/` files. -- Keep each fact on one canonical docs page and link to it elsewhere. The - README is a product overview, not a second configuration reference. -- `Cargo.toml` is the source of the binary version. Release changes must refresh - `Cargo.lock` and keep the release tag check in `tests/release-version.sh` - consistent. - -## Common gotchas - -1. First startup skips existing channel backlog. Tests for startup and cursor - changes must cover both the initial and resumed cases. -2. Slack acknowledges accepted Socket Mode events only after its local inbox - persists them. Keep provider event IDs as the deduplication key. -3. A delivery error after a provider accepts a send can be ambiguous. Do not - claim exactly-once external delivery. -4. Changing a backend for a thread starts a fresh backend session with bounded - history. Never resume a session created by another backend. -5. Live iMessage checks require Full Disk Access for the exact terminal or - service process. Automated tests should use the existing fakes instead. -6. Configuration supports documented legacy migrations. Do not silently - reinterpret removed keys or weaken actionable validation errors. +- Never commit or expose credentials, personal config, message content, + assistant identity, audit logs, databases, cursor state, or session IDs. +- Normal logs must redact content. Content auditing is explicit opt-in and + remains sensitive. +- Runtime state and secrets stay outside the versioned assistant repository. + Preserve path validation, symlink checks, and owner-only permissions. +- Treat every allowlisted sender as an operator of the configured backend. + +## Testing and documentation + +- For bugs, add a regression test for the original cause when practical. +- Cover failure and restart paths when changing persistence, cursors, sessions, + queues, jobs, or delivery. +- Use fakes and local test servers. Automated tests must not require real + credentials, chat data, network services, or installed agent binaries. +- Keep platform behavior explicit and preserve supported non-macOS operation. +- Update canonical documentation and focused tests when public behavior, + configuration, or CLI output changes. +- Edit documentation sources only. Do not edit generated site output or repeat + the same facts across several documents.