Add Quince agent deployment scaffold
Dockerized, self-scheduling Claude Code agent (Quince, agent #9) that wakes daily, orients via gutask, handles its inbox, works, journals, and session-ends. Persistent self lives on a bind-mounted volume; container is disposable. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
# 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, journals, and goes back to sleep.
|
||||
|
||||
The container is disposable. Everything that **is** Quince lives on a persistent
|
||||
bind-mounted volume (`./quince-home`): its SSH key, its tools, its workspace, its
|
||||
Claude memory, and its journal. That is its stable sense of self.
|
||||
|
||||
## How it works
|
||||
|
||||
```
|
||||
┌─ container (disposable) ───────────────────────────────┐
|
||||
│ entrypoint.sh sleep until WAKE_TIME ──► wake.sh │
|
||||
│ │ │
|
||||
│ claude -p (headless) │
|
||||
│ │ │
|
||||
│ reads CLAUDE.md, │
|
||||
│ runs gutask routine │
|
||||
└──────────────────────────────────────────────┼─────────┘
|
||||
│ bind mount
|
||||
┌─ ./quince-home (persistent self) ──────────────▼─────────┐
|
||||
│ CLAUDE.md · .ssh/ · gutasktool/ · workspace/ │
|
||||
│ journal/ · logs/ · .claude/ (memory) │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
Each morning at `WAKE_TIME` it runs `gutask resume → inbox → next/claim → work →
|
||||
journal → session-end`. The routine is defined in
|
||||
[`quince-home/CLAUDE.md`](quince-home/CLAUDE.md) and loaded on every wake.
|
||||
|
||||
## Deploy on the glitch.university server
|
||||
|
||||
```bash
|
||||
# 1. Copy this deploy/ directory to the server, then:
|
||||
cd deploy
|
||||
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. |
|
||||
|
||||
## 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, gutask notes, and its journal. Tighten with
|
||||
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`.
|
||||
```
|
||||
Reference in New Issue
Block a user