Files
tireless/readme.md
rob thijssen ae285f5597
All checks were successful
deploy / deploy (push) Successful in 5m35s
docs: stage 0 complete — agent login done, all three units active
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
2026-08-07 17:59:51 +03:00

101 lines
4.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 18 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.