Add teabot daemon implementation
teabot watches Gitea repos and dispatches one-shot Claude Code sessions in Docker containers to work issues and review PRs, acting as configurable bot personalities. Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
# AGENTS.md
|
||||
|
||||
## Project Overview
|
||||
|
||||
teabot is a Go daemon (systemd **user** service) that watches Gitea repositories
|
||||
and dispatches **one-shot Claude Code sessions in Docker containers** to work
|
||||
issues and review pull requests. It polls the Gitea API for new issues, pull
|
||||
requests, and comments; for each event it runs a throwaway container that clones
|
||||
the repo and runs `claude --print` with a task-specific prompt, acting as a
|
||||
configurable bot **personality**.
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
main.go # package main; wires version into internal/cli
|
||||
internal/cli/ # cobra command tree: run, config init/show
|
||||
internal/config/ # config.yaml + tea-config parsing, defaults, validation
|
||||
internal/gitea/ # read-only Gitea REST client (issues/pulls/comments/diff)
|
||||
internal/state/ # processed-event persistence (JSON, atomic writes)
|
||||
internal/prompt/ # per-event prompt construction (issue/pull/follow-up)
|
||||
internal/dispatch/ # poll loop, event filtering, loop prevention, job orchestration
|
||||
internal/docker/ # containerised Claude execution behind a Runner interface
|
||||
docs/ # architecture + configuration + per-subcommand docs
|
||||
packaging/nfpm.yaml # RPM spec (binary + completions + systemd unit + example config)
|
||||
scripts/build-rpm.sh # generates completions + packages the RPM with nfpm
|
||||
systemd/teabot.service # systemd user unit
|
||||
config.example.yaml # example config (also embedded for `config init`)
|
||||
.woodpecker/ # CI: build, test, pre-commit (PR) + release (tag)
|
||||
```
|
||||
|
||||
## Build / test
|
||||
|
||||
```bash
|
||||
make build # -> dist/teabot (CGO disabled, static)
|
||||
make test # go test -race ./...
|
||||
make rpm # build + package RPM (needs nfpm)
|
||||
```
|
||||
|
||||
Requires Go 1.25+. Deps: `github.com/spf13/cobra`, `gopkg.in/yaml.v3`.
|
||||
|
||||
## Design notes for contributors
|
||||
|
||||
- **Loop prevention is load-bearing.** Any event authored by a personality's
|
||||
Gitea username is skipped (but recorded). Never remove this — it is what stops
|
||||
the bot reacting to its own PRs/comments forever.
|
||||
- **Dedup before dispatch.** Issues/PRs/comments are marked processed in the
|
||||
state store *before* their job starts, so a re-poll or mid-job restart cannot
|
||||
double-launch. State lives at `~/.local/state/teabot/state.json`.
|
||||
- **First-contact seeding.** The first poll of a repo records existing open
|
||||
items as processed without dispatching, so a fresh install doesn't stampede.
|
||||
- **Follow-ups only on acted threads.** Comment follow-ups fire only when teabot
|
||||
previously opened a PR for / reviewed the parent issue/PR.
|
||||
- **Docker is behind `docker.Runner`.** All dispatch logic is tested with a fake
|
||||
runner; no Docker daemon is needed for `go test`. `DockerRunner.buildArgs` is
|
||||
pure given a job dir so the `docker run` argument list is unit-tested directly.
|
||||
- **Personalities use tea configs.** tea persists to `$XDG_CONFIG_HOME/tea` and
|
||||
has no `--config` flag, so each personality's config is mounted into the
|
||||
container and `XDG_CONFIG_HOME` is set there.
|
||||
- **Image reuse.** The default `job_image` is `agent-dev`, which already ships
|
||||
the claude CLI + dev toolchain; teabot does not build its own image.
|
||||
|
||||
## Testing conventions
|
||||
|
||||
Every package has meaningful unit tests (no rubber-stamps): config precedence &
|
||||
validation & tea parsing, state persistence/dedup roundtrips, gitea client via
|
||||
`httptest`, prompt content assertions, docker arg/mount/env construction, and
|
||||
dispatch filtering/loop-prevention/seeding/follow-up routing via a fake client +
|
||||
fake runner. `go build ./...` and `go test -race ./...` must pass.
|
||||
|
||||
## Conventions (house rules)
|
||||
|
||||
- Branches `benvin/<name>`. PR bodies: short "why" paragraph + present-tense
|
||||
"how" bullets. HTTPS remotes for git.unkin.net (SSH blocked). Use `tea`, not
|
||||
`gh`. Do not merge PRs yourself.
|
||||
- Releases are Woodpecker pipelines triggered on `v*` tags; bump with
|
||||
`make patch|minor|major`. Every CI step sets k8s resource requests+limits.
|
||||
Reference in New Issue
Block a user