All checks were successful
deploy / deploy (push) Successful in 5m35s
The interactive login is the one step in stage 0 that cannot be automated, and it is now done. preflight reports a present subscription login; tireless-runner is active alongside the api and poller. Recording it because the previous text said the runner was in `failed`, which was true for about an hour and is now exactly the kind of stale status this repo keeps trying not to leave lying around. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013TxK1CWPkFXqdcXMJ4hVe6
101 lines
4.0 KiB
Markdown
101 lines
4.0 KiB
Markdown
# tireless
|
||
|
||
Keeps several repositories moving without an operator driving each change by
|
||
hand. It watches Gitea (and GitHub, for legacy repos) and does three things:
|
||
|
||
- **discovers** — surveys a repo and proposes issues worth opening;
|
||
- **plans** — decomposes an issue into an epic and child issues, each specified
|
||
well enough for a model that cannot ask questions;
|
||
- **implements** — produces a branch and a pull request.
|
||
|
||
Those chain into a loop with exactly two human gates: **a person decides what
|
||
enters the system, and a person decides what merges.** Discovery proposes but
|
||
never admits its own proposals; nothing merges itself.
|
||
|
||
Two coding agents do the work, each spawned as the vendor's own binary:
|
||
|
||
- **Claude Code** — discovery, planning, and implementation of issues that need
|
||
interpretation. Uses the operator's Claude subscription by default, or
|
||
pay-as-you-go if an API key is supplied.
|
||
- **OpenCode** — implementation of issues that a tireless plan already specified,
|
||
against the self-hosted [helexa](https://git.lair.cafe/helexa/helexa) fleet.
|
||
Never Anthropic; enforced at startup.
|
||
|
||
The rule of thumb: **Claude Code gets judgement, OpenCode gets specification.**
|
||
|
||
Full design, constraints and the staged implementation plan:
|
||
[`doc/plan/design.md`](doc/plan/design.md).
|
||
|
||
## Status
|
||
|
||
**Stage 0 (foundations) is built, deployed and verified.**
|
||
|
||
Working: the domain model, routing, budgets, plan validation, the policy guards,
|
||
configuration loading and validation, the four system prompts, and preflight.
|
||
All three units run on bob, the dashboard is served at
|
||
`https://tireless.internal`, and the deploy workflow is green end to end.
|
||
|
||
Nothing is polled or claimed yet — that is stage 1. The runner is up but has no
|
||
job store to claim from.
|
||
|
||
Not built: Postgres persistence, the forge clients, the poll loop, and every
|
||
agent executor. Stages 1–8 in §7 of the design document say what lands when.
|
||
|
||
tireless is its own first tracked repo — see design.md §10 for what that
|
||
implies, including which parts of this repo are deliberately routed to the
|
||
stronger lane.
|
||
|
||
## Build
|
||
|
||
```sh
|
||
cargo test --workspace
|
||
cargo clippy --all-targets --all-features -- -D warnings
|
||
cargo fmt --all
|
||
|
||
cd dashboard && npm ci && npm run lint && npm run build
|
||
```
|
||
|
||
## Run locally
|
||
|
||
```sh
|
||
cargo run -p tireless-api -- --config ./config.toml
|
||
cargo run -p tireless-worker -- --config ./config.toml poll
|
||
cargo run -p tireless-worker -- --config ./config.toml run
|
||
|
||
cd dashboard && npm run dev # proxies /v1 to 127.0.0.1:23296
|
||
```
|
||
|
||
`tireless preflight` verifies configuration and credentials without starting a
|
||
service: it reports which billing mode a Claude Code run would use and asserts
|
||
the OpenCode lane is not pointed at Anthropic.
|
||
|
||
## Deploy
|
||
|
||
CI-driven via Gitea Actions on merge to `main`
|
||
(`architecture/deployment-gitea-actions.md`). One-time host provisioning —
|
||
including the interactive Claude Code login and the Gitea bot account — is
|
||
`script/infra-setup.sh`.
|
||
|
||
| | |
|
||
| --- | --- |
|
||
| Host | `bob.hanzalova.internal` (binaries, units, job trees) |
|
||
| API port | `23296` (registered in `architecture/port-allocations.md`), bound `0.0.0.0`, mesh-only |
|
||
| Ingress | nginx on the hanzalova proxy — **not** on bob |
|
||
| Dashboard | `https://tireless.internal` (mesh only), served from the proxy |
|
||
| Database | `magrathea.kosherinata.internal:5432`, mTLS |
|
||
|
||
## Conventions
|
||
|
||
Follows [`lair/architecture`](https://git.lair.cafe/lair/architecture);
|
||
`generic.md` is the baseline. Three deliberate deviations:
|
||
|
||
- **`tireless-agent` crate** beyond the standard entities/core/data split.
|
||
Process orchestration is not data access, and it is shared by the runner and
|
||
the CLI. (§1)
|
||
- **`MemoryDenyWriteExecute=false` on `tireless-runner`.** Both agents are Node
|
||
programs and V8's JIT needs write-then-execute pages. The API and poller keep
|
||
the setting. (§8)
|
||
- **`AGENTS.md` is a symlink to `CLAUDE.md`.** Both agents look for their own
|
||
filename and the instructions are identical; a symlink is the only version of
|
||
this that cannot drift.
|