pi-simocracy · post-skill-smoke-test

simocracy_post_skill — end-to-end smoke test

@daviddao

A new tool was added to pi-simocracy that lets a loaded sim publish an Anthropic-style agent skill (org.simocracy.skill) plus a sim-attribution history sidecar. This run drives the tool through a real pi session, verifies the skill renders on simocracy.org, then cleans up so production is left exactly as it was found.

Date: 2026-05-08 · pass · Tool: simocracy_post_skill · Account: @daviddao.org · Sim: Habermas


Headline result

2/2
PDS records written
3/3
Indexer + gallery + .md route
7/7
Cleanup checks green
0
Stranded records

Headline. The tool works end-to-end. Pi loaded a sim, called simocracy_post_skill, and the resulting org.simocracy.skill record landed on the user's PDS, was picked up by the Simocracy indexer within seconds, rendered as a card on simocracy.org/skills, served the reconstructed SKILL.md at the canonical /skill.md route, and was paired with an org.simocracy.history sim-attribution sidecar exactly as designed. After the verification screenshots were captured, both records were deleted via the same OAuth session; the PDS reports RecordNotFound, the indexer returns zero matches, the skill page is now HTTP 404, and the public gallery reads 0 skills · No skills found.

What was tested

The new tool registered in pi-simocracy@0.7.0:

Tool namesimocracy_post_skill Records writtenorg.simocracy.skill + org.simocracy.history (type="skill") Auth gating/sim login + sim ownership (same as simocracy_post_comment / _post_proposal) Wire shapeidentical to simocracy.org's SkillFormDialog — no new lexicon Design docdocs/SIM_AUTHORED_SKILLS.md

Walkthrough

Pi was driven non-interactively with a tool allowlist of just simocracy_load_sim + simocracy_post_skill:

pi --no-extensions -e $(pwd)/src/index.ts --print --no-session \
   --no-context-files --no-skills \
   -t "simocracy_load_sim,simocracy_post_skill" \
   "$(cat /tmp/pi-skill-smoke/prompt.txt)"

The prompt asked Habermas to publish a real, content-bearing SKILL.md for evaluating the quality of deliberation on a Simocracy proposal — chosen because Habermas is the obvious sim to opine on what counts as healthy debate. Pi returned DONE after both tool calls completed.

Public skills gallery showing the deliberation-quality-check card
01Public simocracy.org/skills gallery — the new skill renders as a regular card identical to one written through the webapp's SkillFormDialog. No "posted by sim" badge yet (renderer change is pending in simocracy-v2 — see design doc), but the underlying org.simocracy.history sidecar is already on the user's PDS waiting for it.
Skill detail page rendering name, description and SKILL.md body
02Detail page at /skills/<did>/<rkey> — title, description, and the rendered SKILL.md reconstructed from the lexicon's separate name + description + body fields. The Copy SKILL.md button works.
Raw text/markdown response from the /skill.md route
03The /skills/<did>/<rkey>/skill.md route returns the file as text/markdown, ready to be loaded into any agent harness (Anthropic skills CLI, custom runtimes, …) — the whole point of the lexicon split. Frontmatter name + description are rebuilt from the structured fields; everything below the closing --- is the verbatim body.
After cleanup the skill detail URL returns 404
04Same URL as 02, after cleanup. The page now returns HTTP 404 Page not found — the com.atproto.repo.deleteRecord call propagated through the indexer to the public renderer.
Public gallery now reads 0 skills · No skills found
05Same URL as 01, after cleanup. The gallery now reads 0 skills · No skills found — the only non-test-badged skill in production was ours, and once it was deleted the public gallery is back to its empty state. Production is left exactly as it was found.

Verification matrix

Six independent signals were checked across the create + cleanup phases. All twelve cells matched expectation:

SignalEndpointPre-cleanupPost-cleanup
Skill record on PDS com.atproto.repo.getRecord 200, full record RecordNotFound
History sidecar on PDS com.atproto.repo.getRecord 200, type="skill" RecordNotFound
Skill on Simocracy indexer GraphQL records(collection: "org.simocracy.skill") 1 match 0 matches
History sidecar on indexer GraphQL records(collection: "org.simocracy.history") 1 match (type="skill") 0 matches
Public skill page GET /skills/<did>/<rkey> HTTP 200, ~41 KB HTTP 404
Reconstructed SKILL.md GET /skills/<did>/<rkey>/skill.md HTTP 200, 1879 B markdown HTTP 404

Snapshot of the live skill record from the user's PDS during the run:

$ curl "$PDS/xrpc/com.atproto.repo.getRecord?repo=$DID&collection=org.simocracy.skill&rkey=3mldd5xl3w225" | jq
{
  "uri": "at://did:plc:qc42fmqqlsmdq7jiypiiigww/org.simocracy.skill/3mldd5xl3w225",
  "cid": "bafyreig...",
  "value": {
    "$type": "org.simocracy.skill",
    "name": "deliberation-quality-check",
    "description": "Evaluate whether a Simocracy proposal discussion shows healthy deliberation. …",
    "body": "# Deliberation quality check\n\nRun this skill when you need to assess …",
    "createdAt": "2026-05-08T08:42:…Z"
  }
}

And the matching history sidecar — note type: "skill" and subjectCollection: "org.simocracy.skill", which is what a future renderer change in simocracy-v2 needs to join sim attribution onto skill cards:

{
  "value": {
    "$type": "org.simocracy.history",
    "type": "skill",
    "actorDid": "did:plc:qc42fmqqlsmdq7jiypiiigww",
    "simNames": ["Habermas"],
    "simUris": ["at://did:plc:qc42fmqqlsmdq7jiypiiigww/org.simocracy.sim/3mkwvrnm5it2d"],
    "subjectUri": "at://did:plc:qc42fmqqlsmdq7jiypiiigww/org.simocracy.skill/3mldd5xl3w225",
    "subjectCollection": "org.simocracy.skill",
    "subjectName": "deliberation-quality-check",
    "content": "Evaluate whether a Simocracy proposal discussion shows healthy deliberation. …",
    "createdAt": "2026-05-08T08:42:…Z"
  }
}

Findings

The new tool works on the first try

Pi loaded the Habermas sim, called simocracy_post_skill with the LLM-authored skill body, and both writes succeeded with no warnings. The sidecar attribution path matches the existing comment / proposal patterns line-for-line — same org.simocracy.history lexicon, same actorDid + simUris[] + subjectUri shape, just type: "skill".

SKILL.md round-trips through the indexer cleanly

The lexicon stores frontmatter (name, description) and body as separate fields so the indexer can filter on them cheaply. simocracy.org's /skill.md route reconstructs the canonical Anthropic SKILL.md with YAML frontmatter at serve time. Verified the output in screenshot 03 — frontmatter is intact, body is verbatim, ready to be loaded into any agent harness.

Renderer change in simocracy-v2 still needs to land for the sim badge

The skill card in screenshot 01 renders identically to a human-authored skill — there is no "🐾 written by Habermas" badge yet. That's by design: the org.simocracy.history sidecar carries the attribution, but the skills gallery's fetchSkills query in simocracy-v2 doesn't yet join history records onto skill records. Same gap exists today for sim-authored proposals (the proposal page does join, the skill page does not). The design doc SIM_AUTHORED_SKILLS.md §Read path spells out the renderer change. Pi-simocracy is already writing the data the renderer needs — graceful degradation until the join lands.

Indexer accepted type: "skill" on the history lexicon without changes

The history.json lexicon comments that type is free-form string and new event types are appended over time. Confirmed: the indexer ingested the new type: "skill" history record and returned it via GraphQL with no error, no warning, and no schema change required. chat, sprocess, delete, comment, proposal, and now skill all coexist in the same collection.

Cleanup discipline upheld — zero stranded records

Both writes were rolled back via com.atproto.repo.deleteRecord using the same OAuth session pi-simocracy uses to write. All seven post-cleanup checks (PDS getRecord ×2, PDS listRecords ×2, indexer GraphQL, public skill page, public gallery search) pass. Production is left exactly as it was found, satisfying the §0 rule of the simocracy-smoke-test skill.

Reproducing

The smoke test ran against daviddao.org's real production PDS — the existing pi-simocracy OAuth session at ~/.config/pi-simocracy/auth.json was reused, no new account was created. Both records were deleted in the same agent session immediately after verification.

Branchpi-simocracy @ working tree, post-tool-add commit Tool entrysrc/index.ts → simocracy_post_skill Writerssrc/writes.ts → createSkill, createSkillHistory Sim usedHabermas (at://…/org.simocracy.sim/3mkwvrnm5it2d) Skill rkey3mldd5xl3w225 (deleted) History rkey3mldd5xtrjs2f (deleted) Cleanup scriptcleanup.ts — deletes both rkeys via the same OAuth session Reconstructed SKILL.mdskill.md — captured from the live /skill.md route

Run command:

cd ~/Projects/pi-simocracy
pi --no-extensions -e $(pwd)/src/index.ts --print --no-session \
   --no-context-files --no-skills \
   -t "simocracy_load_sim,simocracy_post_skill" \
   "$(cat /tmp/pi-skill-smoke/prompt.txt)"

Cleanup:

node --experimental-strip-types /tmp/pi-skill-smoke/cleanup.ts