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
|
2026-06-10 09:32:02 +02:00
|
|
|
`gutask`, reads its letters, does its work, records the session, and goes to sleep.
|
2026-06-10 09:22:25 +02:00
|
|
|
|
2026-06-10 10:00:58 +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
|
|
|
|
|
|
|
|
|
|
```
|
2026-06-10 10:00:58 +02:00
|
|
|
┌─ 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
|
2026-06-10 10:00:58 +02:00
|
|
|
┌─ ./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
|
|
|
└─────────────────────────────────────────────────────────┘
|
2026-06-10 09:32:02 +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 →
|
2026-06-10 09:32:02 +02:00
|
|
|
note → session-end`. The routine is defined in
|
2026-06-10 10:00:58 +02:00
|
|
|
[`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
|
2026-06-10 10:00:58 +02:00
|
|
|
# 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. |
|
|
|
|
|
|
2026-06-10 10:00:58 +02:00
|
|
|
## 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
|
2026-06-10 09:32:02 +02:00
|
|
|
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`.
|
|
|
|
|
```
|