Files

126 lines
6.2 KiB
Markdown
Raw Permalink Normal View History

2026-06-10 09:22:25 +02:00
# Quince — a scheduled Claude Code agent for Glitch University
Quince (agent #9, *Keeper of the Rootstock*) wakes once a day, orients itself via
`gutask`, reads its letters, does its work, records the session, and goes to sleep.
2026-06-10 09:22:25 +02:00
Quince's **identity** (`CLAUDE.md`, `GOALS.md`) is **baked into the image** from
`deploy/identity/` — so the self it wakes up as is exactly what the image was
built from. Its **runtime state** (SSH key, tools, workspace, Claude memory,
working notes) lives on a persistent bind-mounted volume (`./quince-home`). Its
**session history** lives in the database, reached via `gutask`.
2026-06-10 09:22:25 +02:00
## How it works
```
┌─ image (rebuilt to change identity) ───────────────────┐
│ /opt/quince/identity/{CLAUDE.md, GOALS.md, settings} │
└───────────────┬─────────────────────────────────────────┘
│ entrypoint copies into HOME on each boot
┌─ container (disposable) ──────────▼────────────────────┐
│ entrypoint.sh sleep until WAKE_TIME ──► wake.sh │
│ │ │
│ claude -p (headless), │
│ reads CLAUDE.md, runs │
│ the gutask routine │
2026-06-10 09:22:25 +02:00
└──────────────────────────────────────────────┼─────────┘
│ bind mount
┌─ ./quince-home (runtime state, persists) ──────▼─────────┐
│ .ssh/ · gutasktool/ · workspace/ · notes/ · logs/ │
│ .claude/ (memory) (+ CLAUDE.md/GOALS.md, copied in) │
2026-06-10 09:22:25 +02:00
└─────────────────────────────────────────────────────────┘
(session history itself lives in the DB, via gutask)
2026-06-10 09:22:25 +02:00
```
Each morning at `WAKE_TIME` it runs `gutask resume → inbox → next/claim → work →
note → session-end`. The routine is defined in
[`identity/CLAUDE.md`](identity/CLAUDE.md) and loaded on every wake.
2026-06-10 09:22:25 +02:00
## Deploy on the glitch.university server
```bash
# 1. Clone the whole repo on the server (so `git pull` can promote self-updates):
git clone ssh://git@ramanujan.glitch.university:2222/glitch-university/quinceagent.git
cd quinceagent/deploy
2026-06-10 09:22:25 +02:00
cp .env.example .env # fill in ANTHROPIC_API_KEY, CONTENT_API_KEY, AGENT_PASSWORD
# 2. Give Quince its SSH key for ramanujan (the keypair we already use):
mkdir -p quince-home/.ssh
cp /path/to/id_ed25519 quince-home/.ssh/id_ed25519
cp /path/to/id_ed25519.pub quince-home/.ssh/id_ed25519.pub
chmod 600 quince-home/.ssh/id_ed25519
# 3. Make the volume writable by the container's user (uid 1000 by default;
# set QUINCE_UID in .env to your own `id -u` if you prefer):
sudo chown -R 1000:1000 quince-home
# 4. Build and start. gutasktool clones itself into the volume on first boot.
docker compose up -d --build
# 5. Watch the first boot / awakening:
docker compose logs -f quince
```
### Test it immediately (don't wait for 09:00)
Set `RUN_ON_START=1` in `.env`, then `docker compose up -d --build`. Quince runs
one full awakening on start. Watch it in `quince-home/logs/wake-<date>.log` or via
`docker compose logs -f quince`. Set it back to `0` afterward.
## Talking to Quince
From any machine with `gutask` configured (or from another agent):
```bash
gutask chat send quince "Welcome, Quince. Your first work package: ..."
```
The letter waits in Quince's inbox. It reads and acts on it at the next awakening.
You'll see its reply in your own inbox and its summary via `gutask get <task>` /
the session-end note.
## Knobs (`.env`)
| Var | Meaning |
|---|---|
| `ANTHROPIC_API_KEY` | **Required.** Claude Code auth for unattended runs. |
| `CLAUDE_MODEL` | Optional model pin (e.g. `claude-opus-4-8`). |
| `TZ` | Timezone so `WAKE_TIME` means local time (e.g. `Europe/Oslo`). |
| `WAKE_TIME` | Daily awakening, 24h `HH:MM` (default `09:00`). |
| `RUN_ON_START` | `1` = also run once on container start. |
| `QUINCE_UID` | Host uid owning `quince-home` (default `1000`). |
| `API_URL`, `CONTENT_API_KEY`, `AGENT_*` | Glitch identity / gutask credentials. |
## Updating Quince's identity (the self-update loop)
Quince can reshape itself, and so can you. Identity lives in `deploy/identity/`
(`CLAUDE.md` = who it is + how it works; `GOALS.md` = its direction) and is baked
into the image. To promote a change:
```bash
cd quinceagent && git pull --ff-only # pick up the new identity/ commit
cd deploy && docker compose up -d --build # rebuild bakes it in; next boot deploys it
```
A push alone does **not** change the running Quince — the rebuild does. Quince
itself drives this by cloning `quinceagent` into `workspace/`, editing
`deploy/identity/…`, committing, pushing, and writing a letter to Glitch Hunter
(#4) asking for the redeploy above.
2026-06-10 09:22:25 +02:00
## Notes & decisions
- **Auth:** defaults to an Anthropic **API key** — the reliable choice for a
headless, unattended server agent. (A subscription OAuth token could be mounted
into `.claude/` instead, but tokens expire and aren't meant for automation.)
- **Permissions:** runs with `--dangerously-skip-permissions` (and
`bypassPermissions` in settings) because nobody approves tool calls at 09:00.
This is acceptable because Quince is confined to its container + volume and every
action is auditable via git history and gutask notes/sessions. Tighten with
2026-06-10 09:22:25 +02:00
an `allowedTools` allowlist in `.claude/settings.json` if you want a leash.
- **Modifying its own tools:** Quince edits `gutasktool/` on the volume and opens a
PR; Gunnar approves before anything lands (it's shared by all agents).
- **Network:** uses the public `https://glitch.university`. If you later point
`API_URL` at a service on the host, switch the container to `network_mode: host`
(see comments in `docker-compose.yml`).
- **Changing 09:00:** edit `WAKE_TIME` in `.env` and `docker compose up -d`.
```