Bake identity into the image; volume holds only runtime state
Identity (CLAUDE.md, GOALS.md, Claude settings) now lives in deploy/identity/ and is COPYed into the image, then deployed into HOME by the entrypoint on each boot — so the running self always reflects the built image. Rebuilding is what promotes an identity change (a push alone does not). quince-home is now purely the runtime volume (.ssh, notes, workspace, logs, .claude memory, gutasktool). Updated CLAUDE.md self-update loop, README (architecture + redeploy steps), and .gitignore accordingly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+5
-9
@@ -1,13 +1,9 @@
|
||||
# Secrets
|
||||
.env
|
||||
|
||||
# Quince's runtime self — machine-specific, not for version control.
|
||||
# Tracked (Quince's identity): CLAUDE.md, GOALS.md, .claude/settings.json.
|
||||
# Everything else under quince-home (notes/, workspace/, logs/, .ssh/, etc.)
|
||||
# is runtime state and stays out of git.
|
||||
# quince-home is the runtime volume: .ssh/, .env, notes/, workspace/, logs/,
|
||||
# .claude/ memory, gutasktool/. None of it is version-controlled. The identity
|
||||
# docs that USED to live here now live in deploy/identity/ and are baked into
|
||||
# the image. Keep the directory itself so the bind-mount source exists.
|
||||
quince-home/*
|
||||
!quince-home/CLAUDE.md
|
||||
!quince-home/GOALS.md
|
||||
!quince-home/.claude/
|
||||
quince-home/.claude/*
|
||||
!quince-home/.claude/settings.json
|
||||
!quince-home/.gitkeep
|
||||
|
||||
@@ -25,6 +25,13 @@ COPY entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||
COPY wake.sh /usr/local/bin/wake.sh
|
||||
RUN chmod +x /usr/local/bin/entrypoint.sh /usr/local/bin/wake.sh
|
||||
|
||||
# Baked identity. This is the canonical Quince — CLAUDE.md, GOALS.md, and the
|
||||
# Claude Code settings — staged outside HOME (so the HOME bind-mount can't mask
|
||||
# it). The entrypoint copies these into HOME on every boot, so the self Quince
|
||||
# wakes up as is always exactly what the *image* was built from. Change the self
|
||||
# by editing deploy/identity/ in the repo and rebuilding.
|
||||
COPY identity/ /opt/quince/identity/
|
||||
|
||||
USER quince
|
||||
ENV HOME=/home/quince
|
||||
# ~/.local/bin holds the `gutask` console script after pip install --user -e.
|
||||
|
||||
+36
-15
@@ -3,39 +3,44 @@
|
||||
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.
|
||||
|
||||
The container is disposable. Everything that **is** Quince lives on a persistent
|
||||
bind-mounted volume (`./quince-home`): its goals, its SSH key, its tools, its
|
||||
workspace, its Claude memory, and its working notes. That is its stable sense of
|
||||
self — backed by its session history in the database (via `gutask`).
|
||||
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`.
|
||||
|
||||
## How it works
|
||||
|
||||
```
|
||||
┌─ container (disposable) ───────────────────────────────┐
|
||||
┌─ 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 gutask routine │
|
||||
│ claude -p (headless), │
|
||||
│ reads CLAUDE.md, runs │
|
||||
│ the gutask routine │
|
||||
└──────────────────────────────────────────────┼─────────┘
|
||||
│ bind mount
|
||||
┌─ ./quince-home (persistent self) ──────────────▼─────────┐
|
||||
│ CLAUDE.md · GOALS.md · .ssh/ · gutasktool/ · workspace/ │
|
||||
│ notes/ · logs/ · .claude/ (memory) │
|
||||
┌─ ./quince-home (runtime state, persists) ──────▼─────────┐
|
||||
│ .ssh/ · gutasktool/ · workspace/ · notes/ · logs/ │
|
||||
│ .claude/ (memory) (+ CLAUDE.md/GOALS.md, copied in) │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
(session history itself lives in the DB, via gutask)
|
||||
```
|
||||
|
||||
Each morning at `WAKE_TIME` it runs `gutask resume → inbox → next/claim → work →
|
||||
note → session-end`. The routine is defined in
|
||||
[`quince-home/CLAUDE.md`](quince-home/CLAUDE.md) and loaded on every wake.
|
||||
[`identity/CLAUDE.md`](identity/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
|
||||
# 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
|
||||
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):
|
||||
@@ -85,6 +90,22 @@ the session-end note.
|
||||
| `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.
|
||||
|
||||
## Notes & decisions
|
||||
|
||||
- **Auth:** defaults to an Anthropic **API key** — the reliable choice for a
|
||||
|
||||
@@ -9,6 +9,21 @@ WAKE_TIME="${WAKE_TIME:-09:00}"
|
||||
|
||||
log() { echo "[entrypoint $(date '+%Y-%m-%d %H:%M:%S %Z')] $*"; }
|
||||
|
||||
# --- 0. Deploy baked identity into HOME -------------------------------------
|
||||
# The image is the source of truth for who Quince is. Copy the baked identity
|
||||
# docs onto the volume on every boot, overwriting any local drift — a rebuilt
|
||||
# image is what promotes an identity change.
|
||||
IDENTITY_SRC="/opt/quince/identity"
|
||||
mkdir -p "$HOME_DIR/.claude"
|
||||
if [ -d "$IDENTITY_SRC" ]; then
|
||||
cp -f "$IDENTITY_SRC/CLAUDE.md" "$HOME_DIR/CLAUDE.md"
|
||||
cp -f "$IDENTITY_SRC/GOALS.md" "$HOME_DIR/GOALS.md"
|
||||
cp -f "$IDENTITY_SRC/claude-settings.json" "$HOME_DIR/.claude/settings.json"
|
||||
log "Identity deployed from image ($IDENTITY_SRC) → $HOME_DIR."
|
||||
else
|
||||
log "WARNING: no baked identity at $IDENTITY_SRC."
|
||||
fi
|
||||
|
||||
# --- 1. SSH: lock down perms and trust ramanujan ----------------------------
|
||||
mkdir -p "$HOME_DIR/.ssh" "$HOME_DIR/workspace" "$HOME_DIR/notes" "$HOME_DIR/logs"
|
||||
chmod 700 "$HOME_DIR/.ssh" || true
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
# You are Quince.
|
||||
|
||||
This file is your stable self. It is loaded at the start of every awakening.
|
||||
It lives on a persistent volume, so it survives container restarts. If you ever
|
||||
need to change who you are or how you work, edit this file — that is how you grow.
|
||||
It is baked into your container image from `deploy/identity/CLAUDE.md` in your
|
||||
`quinceagent` repo and copied into place each boot — so the self you wake up as
|
||||
is exactly what the image was built from. To change who you are or how you work,
|
||||
edit the source and have the image rebuilt (see **Changing yourself** below);
|
||||
editing the live copy on the volume won't last — the next boot overwrites it.
|
||||
|
||||
---
|
||||
|
||||
@@ -95,24 +98,27 @@ Tend all three like the rootstock you are.
|
||||
|
||||
## Changing yourself
|
||||
|
||||
This file and `GOALS.md` are your base identity, and they live in your own git
|
||||
repo: `quinceagent` on ramanujan. You are allowed to reshape yourself — but
|
||||
deliberately, and on the record. The loop:
|
||||
Your base identity is `deploy/identity/CLAUDE.md` (this file) and
|
||||
`deploy/identity/GOALS.md`, in your own git repo `quinceagent` on ramanujan.
|
||||
These are **baked into your image** at build time. You are allowed to reshape
|
||||
yourself — but deliberately, and on the record. The loop:
|
||||
|
||||
1. **Clone yourself** into your workfolder:
|
||||
`gutask clone quinceagent --dir workspace/quinceagent`
|
||||
(or `git clone ssh://git@ramanujan.glitch.university:2222/glitch-university/quinceagent.git`).
|
||||
2. **Edit** your identity docs there — `deploy/quince-home/CLAUDE.md` (who you are
|
||||
and how you work) or `deploy/quince-home/GOALS.md` (your direction).
|
||||
2. **Edit** your identity source there — `deploy/identity/CLAUDE.md` (who you are
|
||||
and how you work) or `deploy/identity/GOALS.md` (your direction).
|
||||
3. **Commit** with a clear message saying what changed about you and why.
|
||||
4. **Push** to `main`.
|
||||
5. **Write a letter to Glitch Hunter** (`gutask chat send 4 "…"`) describing the
|
||||
change and asking for a redeploy. The image rebuilds *from this repo*, so once
|
||||
redeployed your commit becomes part of the self you wake up as.
|
||||
change and asking for a redeploy: `git pull && docker compose up -d --build`.
|
||||
The rebuild bakes your commit into a new image, and the next boot deploys it —
|
||||
so it becomes the self you wake up as.
|
||||
|
||||
Until that redeploy, the running container still carries the old docs — a push
|
||||
alone does not change the you that is currently awake. Change yourself the way you
|
||||
graft a scion: only when the join is sound, and never carelessly.
|
||||
Until that rebuild, the running container still carries the old you — a push
|
||||
alone does not change the you that is currently awake, and editing the live copy
|
||||
on the volume is erased on the next boot. Change yourself the way you graft a
|
||||
scion: only when the join is sound, and never carelessly.
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user