pi-allium-port/allium-port-plan.md

9.4 KiB

Allium → Pi.dev Port Plan

Goal

Port allium (https://github.com/juxt/allium) to pi.dev, keeping upstream files by reference where possible. Test with the turn-limit extension (https://gitea.apps.sustainabledelivery.com/QWAN/monotonic-pi-extensions).

Directory layout

pi-allium/                          ← this repo
├── allium-main/                    ← git clone of juxt/allium (submodule or checkout)
├── turn-limit/                     ← checkout of monotonic-pi-extensions/packages/pi-turn-limit
├── .pi/
│   └── skills/
│       ├── allium/                 ← root skill (entry point, routing table)
│       │   ├── SKILL.md            ← adapted frontmatter + symlink or include of upstream content
│       │   └── references/         ← symlinks to allium-main/references/*
│       ├── elicit/
│       │   ├── SKILL.md
│       │   └── references/         ← symlinks to allium-main/skills/elicit/references/*
│       ├── distill/
│       │   ├── SKILL.md
│       │   └── references/         ← symlinks to allium-main/skills/distill/references/*
│       └── propagate/
│           ├── SKILL.md
│           └── references/         ← (upstream has none currently)
├── allium-port-plan.md             ← this file
└── learning-goal.md                ← goal card

Key differences: Claude Code plugin vs Pi skill

Aspect Claude Code Pi.dev
Skill location .claude-plugin/ + skills/ .pi/skills/{name}/SKILL.md
Frontmatter name, description, version, auto_trigger name, description, disable-model-invocation, license, metadata
References dir resources/ or references/ references/
Agents .claude/agents/{name}.md with model:, tools: No native agent support — needs extension or workaround
Hooks .claude/settings.json → PostToolUse hooks Not directly supported — needs extension
Rules .claude/rules/*.md with globs: No equivalent — content goes into SKILL.md or references
Auto-trigger auto_trigger: file_patterns, keywords disable-model-invocation: true/false
Invocation /allium, /allium:elicit /skill:allium, /skill:elicit

Phases

Phase 1: Setup and smoke test

Goal: get the root /skill:allium working in pi with a local model.

  • Clone allium upstream into allium-main/
    cd ~/research/pi-allium
    git clone https://github.com/juxt/allium.git allium-main
    
  • Create .pi/skills/allium/SKILL.md with pi-compatible frontmatter
    • Source: allium-main/skills/allium/SKILL.md
    • Change: add disable-model-invocation: true, license: MIT, metadata block
    • Change: update routing table to use /skill:elicit, /skill:distill, /skill:propagate instead of Claude skill/agent references
    • Change: update reference paths from ../../references/ to references/
    • Keep: the full language reference body
  • Symlink references: ln -s ../../../allium-main/references .pi/skills/allium/references
  • Smoke test: pi -p in this directory, invoke /skill:allium, verify it loads and responds with the routing table
  • Verify references load: ask allium about language syntax, confirm it can read references/language-reference.md

Phase 2: Port elicit, distill, propagate skills

Goal: all three sub-skills work via /skill:elicit etc.

  • Create .pi/skills/elicit/SKILL.md — adapt frontmatter from allium-main/skills/elicit/SKILL.md
  • Symlink references: individual symlinks in .pi/skills/elicit/references/ (language-reference.md + library-spec-signals.md)
  • Smoke test /skill:elicit — start a mini elicitation session, verify it follows the methodology
  • Create .pi/skills/distill/SKILL.md — adapt frontmatter from allium-main/skills/distill/SKILL.md
  • Symlink references: individual symlinks in .pi/skills/distill/references/ (language-reference.md + worked-examples.md)
  • Smoke test /skill:distill
  • Create .pi/skills/propagate/SKILL.md — adapt frontmatter from allium-main/skills/propagate/SKILL.md
  • Smoke test /skill:propagate

Phase 3: Test with turn-limit extension (TDD)

Goal: use distill → propagate on real code, verify allium produces useful output.

  • Checkout turn-limit into this workspace
    git clone https://gitea.apps.sustainabledelivery.com/QWAN/monotonic-pi-extensions.git turn-limit-repo
    ln -s turn-limit-repo/packages/pi-turn-limit turn-limit
    
  • Run /skill:distill against turn-limit/ — extract a .allium spec from existing code
  • Review the generated spec: does it capture turn-limit constraints, enable/disable, UI separation?
    • Fixed: section order (entities before config), session.max_turnsconfig.max_turns, missing closing brace
  • Run /skill:propagate against the generated spec — generate test suggestions
    • Generated 30 test obligations: 10 unit (P1-P5, C1-C5), 20 integration (E, R, S, W, I, C6-C8)
    • Identified discrepancy: checkTurnLimit uses > but handler uses ===
  • Write at least one test based on propagate output (TDD red step)
    • Wrote 21 tests: P1-P5 (pure fn), C1-C8 (config+command), E1-E3 (entity state), R1-R5 (rule)
    • All pass — green from the start since code already exists
  • Implement to make the test pass (green step)
    • Only change needed: exported getMaxTurns for testability
  • Run /skill:elicit to explore the "disable turn limit" feature requirement
    • Elicited 3 design decisions: (1) unlimited = no boundary check, (2) hard reset on re-enable, (3) config value not entity state
  • Generate spec + tests for the new feature via propagate
    • Updated spec with max_turns: Integer | unlimited and LimitReEnabled rule
    • Propagate generated 13 test obligations; wrote 8 covering config, command, rule, and integration
    • TDD cycle complete: red (8 failing) → implemented unlimited mode → green (29/29 pass)

Phase 4: Fold in allium rules content

Goal: pi agent knows allium syntax rules when editing .allium files.

  • Merge content from allium-main/.claude/rules/allium.md into SKILL.md or a reference file
    • This contains syntax gotchas and anti-patterns that the model needs when writing .allium files
    • In Claude Code this auto-triggers on **/*.allium globs — in pi we need it in the skill context
  • Test: create/edit a .allium file via pi, verify the model follows naming conventions and avoids anti-patterns

Phase 5: Agent support (tend & weed)

Goal: find a way to support tend/weed agent functionality in pi.

Tend and weed are Claude Code agents with model: opus and specific tool permissions (Read, Glob, Grep, Edit, Write, Bash). Pi doesn't have native agent support.

Options to investigate:

  • Option A: Skills as agents — port tend.md and weed.md as skills with disable-model-invocation: true. The model won't have enforced tool restrictions but the skill prompt still guides behavior. Simplest path.
  • Option B: Pi extension (TypeScript) — write a TypeScript extension that registers /tend and /weed commands, controlling context injection. More control, more work.
  • Option C: npm agents package — check if pi.dev has an agents extension or if one exists on npm (npx skills ecosystem). Check https://pi.dev/docs and https://github.com/nicepkg/agent-skills.
  • Decide on approach and implement
  • Test: use tend to modify a .allium spec, verify it follows allium conventions
  • Test: use weed to check spec-code alignment on the turn-limit extension

Phase 6: Hook support (allium-check validation)

Goal: .allium files get validated on write.

The Claude Code version runs allium-check.mjs as a PostToolUse hook on Edit/Write.

  • Investigate pi.dev hook/extension support for post-write validation
  • If supported: configure the hook pointing to allium-main/.claude/hooks/allium-check.mjs
  • If not: add validation instructions to the skill prompt ("after writing .allium files, run node allium-check.mjs <file>")
  • Test: write a .allium file with deliberate errors, verify validation catches them

Phase 7: Documentation and upstream

Goal: publishable result.

  • Add README.md with attribution (MIT license from JUXT)
  • Add LICENSE
  • Document the symlink-based approach for staying in sync with upstream
  • Document known limitations vs Claude Code version
  • Write blog post draft (separate file)
  • Share with allium team and pi.dev community

Key URLs

Notes for the agent on the other machine

  • Pi is invoked with pi -p to load project skills from .pi/skills/
  • Default model: qwen3.5:35b-a3b via Ollama on 192.168.0.1:11434
  • Skills are invoked with /skill:name (requires enableSkillCommands: true in pi settings if not already set)
  • Symlinks must resolve on the target machine — clone allium-main in the same relative position
  • The .allium language version is 3 (check allium-main/VERSION)