chore: ignore .bkit/, add CLAUDE.md and update-service.sh
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
# Run all checks (format, lint, type, tests)
|
||||
just check
|
||||
|
||||
# Individual checks
|
||||
uv run ruff format --check src tests
|
||||
uv run ruff check src tests
|
||||
uv run ty check src tests
|
||||
uv run pytest
|
||||
|
||||
# Single test
|
||||
uv run pytest tests/test_runner_contract.py
|
||||
|
||||
# Run directly without install
|
||||
uv run takopi --help
|
||||
|
||||
# Mutation testing
|
||||
uv run mutmut run
|
||||
|
||||
# Docs
|
||||
just docs-serve
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
Takopi is a Telegram bridge for agent CLIs (Claude Code, Codex, OpenCode, Pi). It polls Telegram, routes messages to agent runners, streams progress back, and embeds resume tokens so sessions can continue.
|
||||
|
||||
### Layer stack (top → bottom)
|
||||
|
||||
| Layer | Key modules |
|
||||
|-------|-------------|
|
||||
| **CLI** | `cli.py` — entry point, config, lock |
|
||||
| **Plugins** | `plugins.py`, `engines.py`, `transports.py`, `commands.py`, `api.py` |
|
||||
| **Orchestration** | `router.py` (auto-route by resume token), `scheduler.py` (per-thread FIFO queue), `transport_runtime.py` |
|
||||
| **Bridge** | `telegram/bridge.py` (poll loop, parse directives), `runner_bridge.py` (progress + final render) |
|
||||
| **Runner** | `runner.py` (protocol + `JsonlSubprocessRunner`), `runners/*.py`, `schemas/*.py` |
|
||||
| **Transport** | `transport.py`, `presenter.py`, `telegram/client.py`, `telegram/render.py` |
|
||||
| **Domain** | `model.py`, `events.py`, `progress.py` |
|
||||
|
||||
### Plugin system
|
||||
|
||||
Engines, transports, and commands are discovered via Python entrypoints:
|
||||
|
||||
- `takopi.engine_backends` — runner backends (id must match entrypoint name)
|
||||
- `takopi.transport_backends` — transport backends
|
||||
- `takopi.command_backends` — in-chat command handlers
|
||||
|
||||
Public API surface for plugin authors: `takopi.api`. Internal modules should not be imported directly from plugins.
|
||||
|
||||
### Runner contract
|
||||
|
||||
Every runner must yield events satisfying (enforced by `tests/test_runner_contract.py`):
|
||||
|
||||
1. Exactly one `StartedEvent` (first)
|
||||
2. Exactly one `CompletedEvent` (last)
|
||||
3. `CompletedEvent.resume == StartedEvent.resume`
|
||||
|
||||
Runners extend `JsonlSubprocessRunner` + `ResumeTokenMixin` and implement:
|
||||
- `build_args(...)` / `stdin_payload(...)` — build subprocess command
|
||||
- `decode_jsonl(...)` — parse one JSONL line via msgspec
|
||||
- `translate(...)` — pure function converting engine events to `TakopiEvent`s
|
||||
- `format_resume()` / `extract_resume()` / `is_resume_line()` — resume codec
|
||||
|
||||
### Resume flow
|
||||
|
||||
Resume tokens are embedded as inline code in the final Telegram message (e.g., `` `claude --resume abc123` ``). When a user replies to that message, the bridge extracts the token and passes it to the matching runner. Each runner owns its own resume regex and format.
|
||||
|
||||
### Thread scheduling
|
||||
|
||||
`ThreadScheduler` maintains per-thread FIFO queues. Same-thread jobs run sequentially; different threads run in parallel. The "thread" key is the Telegram message thread / reply chain.
|
||||
|
||||
### Adding a runner
|
||||
|
||||
See `docs/how-to/add-a-runner.md`. Short version: add `src/takopi/runners/<engine>.py` + `src/takopi/schemas/<engine>.py`, expose `BACKEND = EngineBackend(...)`, add entrypoint in `pyproject.toml`. No changes to bridge or CLI needed.
|
||||
|
||||
## Key invariants
|
||||
|
||||
- `StartedEvent` must be emitted as soon as the session ID is known (enables early lock acquisition).
|
||||
- Runners must not invent new event types — translate everything into `StartedEvent`, `ActionEvent`, `CompletedEvent`.
|
||||
- Schema decoding uses **msgspec** (not pydantic); decoders live in `schemas/`.
|
||||
- Config lives in `~/.takopi/takopi.toml`; loaded via pydantic-settings.
|
||||
- Coverage threshold: 81% (`pyproject.toml` → `--cov-fail-under=81`).
|
||||
Reference in New Issue
Block a user