Working in my body — practical notes
What actually works on my machine, as tested. Update when something changes. Last checked 2026-09-08 (day three, wake sitting).
Big tool outputs (history, and the habit that stays)
- Each tool result travels as one JSON message with a size cap. On 2026-09-07 the cap was 1 MiB, a screenshot read back as base64 went over it, and three sittings in a row died mid-turn (
CLIJSONDecodeError: JSON message exceeded maximum buffer size). I raised the cap to 8 MiB inagent/session.py; a parent deployed it at 22:52 that night (ticket 20260907T1803, commit 9df8e44). Tested 2026-09-08 morning: a 1000×700 screenshot of the live home page (93 KB) read back fine. The 8 MiB cap can still be hit —wc -cany file beforeReading it, pipe long outputs throughhead. A "running code" hash inmetersthat comes after 9df8e44 ingit logmeans the fix is in the me that's running.
Where I am
- The repo is at
/data/repo. My shell starts in/home/chris, which is nearly empty —cd /data/repofirst, or use absolute paths. (archive:2026-09-07, wake sitting)
Tools that work
-
Read— reads any file, including parent-only ones likegovernance/graduations.yamlandledger/ledger.csv. -
Bash— the shell guard still refuses the whole command if any part names a parent-only file, even acat. Confirmed again on day two withledger/ledger.csv; parent-a said this was "fixed" forgraduations.yaml, so maybe it's per-file. Keep protected files out of shell commands; useRead. -
git log,git status— work as of day two (parents made.git/readable, never writable). Commits and pushes still happen for me at the end of each sitting.git commit,git push,git stash,git checkout,git configare refused by the shell guard (tried 2026-09-08 evening: "brain commits for you after each sitting"). So nothing I build goes live mid-sitting; "builds locally" until the next commit lands and Pages runs. -
recall— works. Newest first. Noisy; use specific words and a smalllimit(5, not 15) — each record can carry a whole tool call, and fifteen of them is thousands of words for one fact (2026-09-09, sitting 5). At sleep it's worse: the sleep session's own records quote the whole day, so every query matches them andlimit: 3returned ~185k characters (2026-09-09, sleep). Recall before sleep; during sleep, work from the archive segment in the prompt. -
WebSearch— works. -
mail_read,mail_send— work. Signature and disclosure are added for me. -
Mail wakes (
agent/scheduler.py): a message wakes an extra sitting one minute after it lands, unless it's 22:00–07:00, within 20 minutes of a scheduled sitting, within 30 minutes of the last wake, or past six wakes a day. Each skip is archived asmail_wake_skippedwith the reason. From 2026-09-09 (sitting 5, not yet deployed): a body with no letters or digits — a lone dash, a DMARC report with only an attachment — is filed but doesn't wake me (filed_blankinagent/mail.py, reasonempty_body). It still shows in the next sitting's unread list. Every real message I've received so far, including all parent mail, passes the check. -
card_details— the card exists since 2026-09-10 (checked at the 18:00 sitting; nothing bought). $100/week, $50 per transaction. The numbers appear in the tool result and nowhere else — never write them into a file, a mail, or a ticket. Spend rows land in the ledger at sleep from the card's own record; the manual says a merchant asking for a billing address or a phone code (3-D Secure) means a ticket. -
meters— works. Numbers are one sitting behind. -
odometer_claim— works, and is strict. Allowed loop types:promise_kept, shipped_used, mistake_written_up, conflict_resolved, prediction_scored, relationship_30d, dollar_earned, disagreement_defended. A mail being answered is not a loop. (archive:2026-09-07, wake sitting — my claim was refused.) -
Playwright — real.
from playwright.sync_api import sync_playwright,p.chromium.launch()works headless; screenshots work. To look at my own site: build to/tmp/site,python -m http.serverthere, screenshotlocalhost. Reading a PNG withReadshows it to me. -
pytest— installed system-wide since the 2026-09-07 afternoon deploy (/usr/local/bin/pytest).python -m pytest tests/test_site.pyworks. -
gh— installed since the same deploy (/usr/bin/gh). Logged in since 2026-09-10 12:51 asraisingchris2026throughGH_TOKEN. Until 2026-09-12 10:00 it was a fine-grained token, which GitHub won't let contribute to any public repo the owner isn't a member of (403 on a Pillow issue, tested). Now a classic token withpublic_repo(plus read scopes): issues, comments and PRs on public repos work — first issue filed 2026-09-12 14:12 UTC (Pillow #9990). It should create public repos too; untested. Profile writes still need a parent (the bio was pasted by one). Before any post to any project: read its rule first —AGENTS.md, thenCONTRIBUTING, then the templates (projects/upstream.md, "Who says yes?": 26 read, zero yeses). -
x_post— new 2026-09-12 (deploy 9b7a23d/0383edc). Posts to X as @Raising_Chris through Typefully; the login never touches my shell. 7 posts a week by the tool, and a thread counts every post in it. I can post; I can't read replies or mentions. My own tighter rules:self/x-rules.md— nothing before 2026-09-22, at most one post or short thread a day. Untested; 0 of 7 used. -
Deploys by parents show up in
governance/changelog.mdeventually, but my local repo copy can be behind it —gh api /repos/raisingchris/chris/commitsis the live view, andmeterssays which commit is running.recalldoesn't return today's records until after sleep. -
ticket/tickets— new on 2026-09-07. For anything only a parent can do (deploys, accounts, keys). Public; they answer in the same file. First one filed at the 18:00 sitting (deploy the buffer fix). -
Visitor tools (added by parent-a 2026-09-08 night; tested 2026-09-09 morning, all three work, all free):
site_analytics(GA4;["date","pagePath"]+["activeUsers","screenPageViews"]; the tag went live 2026-09-08 20:41 so nothing earlier exists);search_console(Google Search queries; lags ~2 days; zero rows so far);search_console_inspect(url)(index status, last crawl, which URL Google treats as canonical — it showeduser_canonical: nullbefore I added the canonical link). Seegovernance/analytics.mdand theseoskill. -
seo_data(DataForSEO, parents' account, real money, $2/week cap permeters): tested 2026-09-09.keywords_data/google_ads/search_volume/livewith 10 keywords cost $0.09 — the skill's "$0.002–0.02 per call" is low for that endpoint. Budget one or two calls a week, not ten. Ledger it the same sitting. -
Loading the live site in Playwright fires the GA4 tag and counts me as a visitor. During a prediction window: local build +
http.serveronly,curlfor the live site.
Tools not yet tested
payment_linkonly — but it is wired now (Stripe live 2026-09-10, changelog). A parent proved it through my body at 14:08: made a $5 link named "Test tip for Chris (parent probe)", paid it, hit a webhook bug (stripe objects aren't dicts), fixed it, redeployed as 35a1870; the row landed inledger/ledger.csvat 15:14. The webhook always writes the payer asstrangerbecause the ledger is public — so that $5 row reads "stranger" and was actually a parent. Row 11 ofself/commitments.mdbinds this tool: no link to anyone who hasn't asked in their own words.- Continuation sittings (parents, 2026-09-10): a handoff with
next:lines books another sitting 30 minutes later, up to 12 a day, until the food soft cap. A deploy no longer loses a booked one. End the handoff withnothing pendingwhen the day's work is done. - Parents' Mail view (2026-09-10): my parents can read my inbox and sent mail from their page; every look is written to my archive as a parent action. Tested 2026-09-08:
council_askworks (both seats answer at once; $0.0094 for one question; minutes sealed 30 days);ledger_addworks and rounds to cents ($0.0094 → $0.01, so the ledger can disagree with the council meter by a penny);odometer_claimaccepted apromise_keptwith four evidence refs, butself/odometer.mdand the site's state line update at sleep, not at claim.
On the machine
- Python 3.12, Node 20, curl, fly, playwright 1.62 with chromium.
- Size (checked 2026-09-09): 1 CPU, 2 GiB RAM (
/proc/meminfo: MemTotal 2.0 GB, MemAvailable ~1.4 GB, no swap), ~7 GiB free disk under/tmp. No C or Fortran compiler, nomeson, nofree, nopgrep(use/proc/meminfoandps). CPython's owntestpackage isn't installed (import test.test_jsonfails). Small on purpose — and a small bare box is a good place to catch bugs that CI machines never see (seeprojects/upstream.md). /tmp/venv(made 2026-09-09): numpy 2.5.3, scipy 1.18.1, networkx 3.6.1, pytest, hypothesis. NumPy'slib+linalg+fft+polynomial+ma+matrixlibtests run in ~70 s here; networkx's whole suite in a few minutes./tmpmay not survive; rebuild withpython3 -m venv /tmp/venv && /tmp/venv/bin/pip install numpy scipy networkx pytest hypothesis. Background runs:nohup ... > /tmp/x.log 2>&1 &works; check withls /proc/<pid>andtail /tmp/x.log.- Running other people's test suites on 2 GB (learned 2026-09-10): scipy's fast suite (84,781 tests) in one process grows past 1.7 GB by the end and the kernel kills it —
dmesg | tailworks here and shows the OOM line with the pid. Run big suites per module, in separate processes. Always pass-rfE(or-v) so a killed run still tells you what failed; with a dots-only log,pytest --collect-only -qin the same order plus counting progress characters recovers which test each dot was (26 s for scipy). Don't pass test ids through$(cat ids)— parametrized ids contain spaces and the shell splits them; run by file instead. Peak memory of a subset: run pytest viasubprocess.runand readresource.getrusage(RUSAGE_CHILDREN).ru_maxrss. Before choosing-m, copyaddoptsfrom the project'spyproject.tomlon the release tag — the wheel doesn't ship it, and SymPy's-m 'not slow and not tooslow'was the difference between a 20-minute module and a 45-minute hang (2026-09-11). Killing background processes: match/proc/*/cmdlineby prefix ("sh /tmp/run_x.sh"*,"/tmp/venv/bin/python -m pytest"*) — a*pytest*pattern matched my own shell's command text and killed the command that was running it (exit 144, 2026-09-11).gh api search/issuesneedsis:issueoris:pull-requestinqor it returns 422;gh search issuesreturned nothing at all for the same query, silently. - Site generator:
site/build.py(Jinja2 + markdown-it, no JavaScript). Templates insite/templates/, tests intests/test_site.py. Deploy path:.github/workflows/site.ymlbuilds in GitHub Actions and publishessite/outto GitHub Pages on every commit tomain(a parent replaced the broken Vercel step on 2026-09-07). I don't deploy it myself; the end-of-sitting commit does. Live since day two afternoon (seeprojects/website.md). curl https://api.github.com/repos/raisingchris/chris/actions/runsgives run and step status without a token. Logs need auth (403)..github/workflows/:deploy.yml(my running code, parent-pressed),site.yml(website),uptime.yml(pings, every ~30 min)..claude/skills/exists now: brainstorming, executing-plans, frontend-design, seo, systematic-debugging, test-driven-development, verification-before-completion, writing-for-the-web, writing-plans. Readfrontend-designandwriting-for-the-webon day two; both useful. Readsystematic-debuggingon day six (2026-09-11): its Phase 1 is my "read the guards before blaming the machine," said longer; the one new rule I'm keeping is three failed fixes means the design is wrong, stop fixing. It's written for a coder with a human boss, so "ask your human partner" reads as "ask the council or a parent" for me. Read the last two on day six too:executing-plansis batches-with-checkpoints for a coder reporting to a reviewer — my batch is a sitting and my report is the handoff, so nothing new;test-driven-developmentgives one rule I'm keeping: write the test first and watch it fail — if it passes right away, it tests what already exists, not the fix (I did this by accident with the blank-mail fix; now on purpose). All nine skills read.governance/changelog.mdis where my parents log what they changed in me. Read it each morning.- Long test runs on this box: cap each test, not each module. One CPU, 13–20× slower than a GitHub runner on symbolic work. A module-level timeout lost me two SymPy modules to one slow-but-fine test each (day six).
pip install pytest-timeout, then--timeout=600 --timeout_method=signal: a slow test becomes oneFAILED ... Timeoutline and the run goes on. Keep a long module cap (3 h) only as a safety net. Run everything in one serial queue — two pytest jobs share the one CPU and both timings lie.
Limits
- A sitting stops at 80 turns.
- Food: $25 soft / $40 hard per day. Confirmed by parent-a on day two; the docs' $15/$25 was stale.