A human-governed control plane for parallel AI software teams.
Coordinate multiple people and AI agents on one codebase without mixing project state, identity, context, memory, or working trees.
Quick start · How it works · Current status · Architecture decisions
Zero Develop is not another single-agent coding CLI. It is the authoritative backend for a collaborative development system where humans approve plans and specialized agents execute a durable task graph in isolated Git worktrees.
The project keeps the important things outside model context: identity, authorization, plans, execution state, project memory, retrieval provenance, tool policy, provider accounting, and audit history. Models and interfaces can change without becoming the source of truth.
Important
This repository is an audited Phase 9 development checkpoint, not a production release. Core contracts are exercised by deterministic local tests. Live provider and messaging integrations, production deployment, and several concurrency hardening requirements remain unverified. See Current status before adopting it.
| Principle | What it means in practice |
|---|---|
| Humans authorize execution | No execution starts until an authorized human approves a specific plan revision. |
| Parallel work stays isolated | Concurrent tasks use separate branches and Git worktrees rather than sharing a writable directory. |
| One control plane, many interfaces | The website, API, and messaging adapters project the same backend state and policy. |
| Agent teams follow the project | Project-specific agent types can be created, split, merged, retired, and rolled back with knowledge provenance. |
| Context is a budgeted view | Project RAG, retrieval ledgers, named context regions, and compaction operate on canonical project records. |
| Trust is enforced server-side | Stable IDs, project-scoped authorization, capability grants, secret references, and append-only audit events do not depend on UI hiding or agent self-report. |
flowchart LR
H[Human team] --> W[Web control surface]
M[Messaging clients] --> N[Canonical interface events]
W --> C[FastAPI control plane]
N --> C
C --> P[Versioned plan + approval gate]
P --> X[Durable execution graph]
X --> G[Isolated branches + worktrees]
G --> I[Impact-aware integration review]
I --> S[(Canonical project state)]
C --> S
S --> R[Artifacts, project RAG + context]
S --> A[Append-only audit]
C --> T[Tools, secrets + provider policy]
A change moves through the system as an evidence-bearing workflow:
- A human request becomes a canonical conversation event.
- The planning boundary creates a versioned proposal tied to source events.
- An authorized human approves, rejects, or revises the exact current revision.
- The worker converts an approved handoff into a dependency-aware task graph.
- Ready tasks run in isolated Git worktrees with command, diff, and test artifacts.
- Integration review checks the impact set, contracts, combined tests, and human conflicts.
- Only accepted changes may update integrated state, project knowledge, and audit history.
The current source tree contains working local implementations for:
- Identity and project isolation — stable Zero user IDs, external identity links, memberships, and project-scoped access.
- Authorization and audit — backend permission checks, append-only redacted events, and correlation-aware history.
- Plans and execution — immutable plan revisions, approval/rejection gates, durable task dependencies, retries, cancellation, snapshots, and restart recovery.
- Isolated development — repository registration, branch/worktree creation, command execution, diff capture, and cleanup protections for uncommitted human work.
- Dynamic agent topology — project-specific agent types, concurrency limits, knowledge records, split/merge/retire operations, snapshots, and rollback.
- Artifacts and context — content-addressed artifacts, project-scoped RAG, retrieval provenance, token budgets, context versions, and compaction records.
- Tools, secrets, and providers — capability-scoped tool grants, encrypted secret storage, canonical provider contracts, request deduplication, and usage accounting.
- Integration and interfaces — impact-aware merge gates, an HTML control surface, REST API, and canonical Telegram/Discord-style event contracts.
- Operational foundations — health/readiness probes, low-cardinality metrics, secret-canary scans, backup/restore helpers, and recovery services.
The web surface includes project, membership, plan, execution, agent-topology, and audit views.
Interactive API documentation is available from the running application at /docs.
- Git
- uv — manages the required Python 3.12+ environment
git clone https://github.com/mhrsdev/zero-agent-dev-telegram.git
cd zero-agent-dev-telegram
uv venv --python 3.12
source .venv/bin/activate
uv pip install -e ".[dev]"
export ZERO_ENV=development
zero-develop serve
# Bare start also works: with ZERO_ENV unset, `serve` assumes the
# development defaults above (local SQLite, loopback bind) and prints
# a notice. Production still requires explicit configuration.
# zero-develop serve --host 127.0.0.1 --port 8000Open:
- Web control surface: http://127.0.0.1:8000/web/
- Interactive API docs: http://127.0.0.1:8000/docs
- Health probe: http://127.0.0.1:8000/healthz
- Readiness probe: http://127.0.0.1:8000/readyz
You can also start the ASGI application directly:
ZERO_ENV=development uvicorn zero.main:app --reloadZERO_ENV=test PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=src \
python -m pytest -rA -p no:cacheprovider
ruff check --no-cache src tests scripts
ruff format --check --no-cache src tests scripts
PYTHONDONTWRITEBYTECODE=1 python -m compileall -q src tests scriptsThe test suite uses isolated SQLite state and exercises the same application factory used by the
runtime. The current baseline is 1107 passed, 0 failed, 48 skipped. Skips are honest
environment gates, not silenced failures: platform-specific POSIX cases, optional extras
(tokenizer, pg), credential-gated live tests, and suites that drive a real loopback HTTP
server — those last ones probe for a working loopback round trip first and skip only where the
environment cannot complete one, so a genuine adapter regression still fails.
Tests never read your real $ZERO_HOME: a session fixture redirects it to a throwaway directory.
Without that, a configured owner_only access policy in ~/.zero/config.yaml denies every
interface intake in the suite, and home-writing tests mutate your live configuration.
A release build must also pass the clean-artifact gate. Build from a clean committed Git tree so untracked or dirty checkout files cannot enter the release:
release_source="$(mktemp -d)"
rm -rf dist
mkdir -p "$release_source"
test -z "$(git status --porcelain --untracked-files=all)"
git archive --format=tar HEAD | tar -x -C "$release_source"
python -m build --outdir dist "$release_source"
python "$release_source/scripts/validate_release_artifacts.py" distThat gate checks the wheel and source distribution independently for all 34 migration files and the runtime modules required by the application entry point.
Configuration is a typed, fail-closed trust boundary. The console and ASGI entry points read
process environment variables; .env.example is a reference template and is not loaded
automatically. Never commit a real .env.
| Variable | Required | Purpose |
|---|---|---|
ZERO_ENV |
Always | Selects development, test, or production. |
ZERO_DATABASE_URL |
Production | Explicit database location; development and tests receive isolated defaults. postgresql:// requires the [pg] extra. |
ZERO_SECRET_KEY |
Production | Secret material of at least 32 bytes; redacted from representations and logs. zero setup bootstraps $ZERO_HOME/secret.key + .env when absent. |
ZERO_LOG_LEVEL |
No | DEBUG, INFO, WARNING, or ERROR. |
ZERO_AUTH_REQUIRED |
No | Defaults to enabled in production and disabled elsewhere. |
ZERO_BOOTSTRAP_TOKEN |
When protected bootstrap is used | Authorizes first-user bootstrap without storing the raw token in application state. |
ZERO_PANEL_PORT |
No | Port for the engine/admin GUI (default 8000); the TUI reads the same value. |
ZERO_SANDBOX_EXECUTOR |
No | none (default), docker, or firejail. Required for worktree commands in production. |
ZERO_SANDBOX_IMAGE |
No | Pinned container image for the docker sandbox (default python:3.12-slim). |
ZERO_TELEGRAM_MODE |
No | bot_api (default) or explicit user_session opt-in (needs [session] extra). |
ZERO_TELEGRAM_API_BASE |
No | Override for Bot API base (self-hosted gateways / tests). |
ZERO_MCP_SERVERS |
No | JSON array of MCP stdio servers to expose as tools. |
ZERO_CHAT_RATE_LIMIT_PER_MIN |
No | Admin chat endpoint budget per minute (default 10). |
ZERO_DECOMPOSITION_ENABLED |
No | Opt-in LLM plan decomposition (1/true). |
ZERO_TOOL_APPROVAL_MODE |
No | Per-call tool approval gate (off default / manual). Manual mode consults a durable gate before every declared tool call in task executions: hardline floor, deny rules outrank allows, pending queue answerable at GET/POST /projects/{id}/tool-approvals. |
ZERO_PG_POOL_MIN / ZERO_PG_POOL_MAX |
No | PostgreSQL pool bounds (defaults 2/20). |
ZERO_ENABLE_LIVE_TESTS |
No | Must be 1 plus credentials to run tests/integration_live. See docs/LIVE_TESTING.md. |
Optional extras: [tokenizer] tiktoken counting, [pg] PostgreSQL,
[mcp] Model Context Protocol, [session] user-session Telegram,
[tui] terminal UI.
Production mode refuses missing secrets, in-memory persistence, and development database paths. See ADR 0004 for the full contract.
A Telegram bot token is embedded in every Bot API request URL, so a captured engine log is a
credential. .gitignore excludes *.log for exactly this reason, and
tests/test_hardening_wave8.py::test_no_live_credentials_in_tracked_files scans every tracked
text file for Telegram-token, OpenAI-key, AWS-key, GitHub-PAT, and Slack-token shapes so a commit
cannot reintroduce one.
The e2e and evidence drivers under scripts/ and realrun-evidence/ read their credentials from
the environment and fail closed by variable name when one is absent:
export E2E_BOT_TOKEN=... # scripts/e2e_round5_*.py|sh
export E2E_PROVIDER_KEY=...
export E2E_WEBHOOK_SECRET=...
export REALRUN_BOT_TOKEN=... # realrun-evidence/*
export REALRUN_API_KEY=...If a credential does reach a commit, rotating it is the only fix that matters — revoke a bot token through @BotFather and reissue provider keys. Scrubbing the working tree does not invalidate what is already in published history.
VERIFIED means deterministic local verification in the Phase 9 source tree. It does not
mean production readiness.
| Area | State | Evidence boundary |
|---|---|---|
| Identity and project isolation | Verified | Backend and authenticated HTTP isolation tests |
| Authorization, secrets, tools, and audit | Partial | Core policy and redaction pass; arbitrary in-process handler timeouts are unsupported |
| Plans and durable execution | Partial | Lifecycle, graph, retry, and recovery pass; concurrency races remain |
| Git worktree isolation | Verified | Local Git/worktree tests |
| Dynamic agent topology | Partial | Lifecycle and rollback pass; concurrency and complete knowledge rollback need hardening |
| Artifacts, RAG, context, and compaction | Verified | Deterministic local isolation and rebuild tests |
| Provider boundary and accounting | Partial | Deterministic fake adapter only; no live provider or billing truth |
| Integration review and controlled merge | Verified | Local impact, contract, combined-test, and provenance gates |
| Website and messaging interfaces | Partial | ASGI and canonical-event tests; no browser audit or live Telegram/Discord run |
| Operations and rollout | Partial | Recovery helpers pass; production rollout and encrypted product backup are blocked |
Read the full audited current-state ledger and Phase 9 closeout report for claim-level evidence.
The latest pass found and fixed a set of real defects; each is pinned by a test in
tests/test_hardening_wave8.py. Full detail is in the changelog.
- Live credentials had been committed — a Telegram bot token and a provider API key, both in captured logs and as hard-coded script constants. Scrubbed, untracked, and now guarded by a scanner test; see Never commit credentials.
- The admin GUI's CSRF token was derivable from the session id (
sha256("csrf:" + sid)), so a leaked session id yielded the matching token. Tokens are now random per session. DockerExecutorpassed the whole host environment to thedockerCLI. The container environment was already scrubbed; the wrapper process is now limited toPATH, locale, and the Docker daemon locators.- The auth middleware blocked the event loop on two synchronous database reads per authenticated request; both now run in the threadpool, as the routers already did.
Databaseleaked its cached SQLite connections, producingResourceWarning: unclosed databaseon CPython ≥ 3.13 and non-deterministic failures under the warnings-as-errors policy.- The reported version was three release lines stale — the package said
0.1.0at v0.8.5, so the wheel,/healthz,--version, and the MCP handshake all disagreed with the tree.zero.__version__is now the single source of truth.
Production rollout is deliberately blocked until at least the following are complete:
- encrypted product-level backups and a rehearsed restore procedure;
- live provider, Telegram, and Discord validation;
- browser, mobile, and accessibility testing;
- concurrency and linearizability hardening around plan approval, task claiming/completion, agent limits, provider idempotency, and topology rollback;
- production deployment, TLS, supervision, external persistence, and disaster-recovery rehearsal;
- a clean tracked-artifact build and installed-wheel startup gate;
The current BackupService produces an authenticated encrypted backup only when a stable configured
ZERO_SECRET_KEY is available. Without that encryption authority, backup and restore fail closed.
zero-agent-dev-telegram/
├── docs/
│ ├── decisions/ # 26 architecture decision records
│ ├── gap-designs/ # capability gap designs (GAP 01–12)
│ ├── CURRENT_STATE_LEDGER.md
│ ├── REQUIREMENT_LEDGER.md
│ └── PHASE_*_CLOSEOUT.md
├── src/zero/
│ ├── domain/ # canonical types, invariants, and state transitions
│ ├── app/ # application services and FastAPI boundary
│ │ ├── routers/ # per-domain HTTP routers (assembly stays in api.py)
│ │ ├── executors/ # sandbox command backends (docker / firejail / host)
│ │ └── clock.py # the one canonical UTC timestamp format
│ ├── persistence/ # repositories + 34 ordered migrations (SQLite and PostgreSQL)
│ ├── web/ # server-rendered control surface
│ ├── manage/ # operator CLI, admin GUI, TUI, setup wizard
│ ├── adapters/ # transport/provider adapter boundary
│ ├── config.py # typed configuration trust boundary
│ └── main.py # ASGI and console entry point
├── tests/ # deterministic unit, HTTP, integration, and E2E tests
│ └── integration_live/ # credential-gated live provider/Telegram tests
├── scripts/ # development, release, and e2e helpers
├── realrun-evidence/ # real-credential run drivers and captured evidence
└── pyproject.toml
Dependency direction stays inward: interfaces and adapters call application services; domain rules remain the canonical center; persistence implements the storage boundary.
- Usage & operations guide — install, configure, run, and drive the full workflow
- Changelog — every fix wave with the failure each item corresponds to
- Requirement ledger — confirmed behavior, invariants, and evidence
- Current-state ledger — verified, partial, and blocked areas
- Dependency map — safe milestone and capability ordering
- Architecture decisions — 26 ADRs covering identity, execution, context, providers, integration, interfaces, security, and rollout
- Live testing — credential gates for the live provider/Telegram suites
- Phase 9 closeout — latest verification and rollout decision
Changes should preserve the control-plane invariants:
- do not start execution without an approved, current plan revision;
- do not share writable workspaces between concurrent tasks;
- do not use display names, usernames, routes, or UI state as authority;
- do not expose raw provider, tool, or user secrets to model context or audit logs;
- do not commit a credential, or a log that embeds one, in any form;
- do not block the event loop on database or network I/O in an
asynchandler — the routers are synchronous on purpose and run in the threadpool; - do not update memory or RAG from rejected or unintegrated work;
- do not report planned capability as implemented capability.
Before opening a change, run the verification commands above and update the current-state ledger when the evidence boundary changes.
This project is MIT-licensed; see the root LICENSE file.