
Autostar
- 19 installs
- 39 repo stars
- Updated April 9, 2026
- chrisvoncsefalvay/autostar
Provides autostar capabilities for Claude Code workflows.
About
autostar enables Provides autostar capabilities for Claude Code workflows.. Use it to automate and enhance your development workflow with AI-powered capabilities.
- Enhances Claude Code
- Production-ready
Autostar by the numbers
- 19 all-time installs (skills.sh)
- Ranked #1,568 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Jul 28, 2026 (Skillselion catalog sync)
npx skills add https://github.com/chrisvoncsefalvay/autostar --skill autostarAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 19 |
|---|---|
| repo stars | ★ 39 |
| Last updated | April 9, 2026 |
| Repository | chrisvoncsefalvay/autostar ↗ |
What it does
Provides autostar capabilities for Claude Code workflows.
Files
a* (autostar)
A generalised autonomous optimisation loop — soft RLVR for the masses. The user defines a goal; the system runs structured experiments, evaluates progress across independent tracks, reflects at strategic checkpoints, and learns from every attempt — including learning how to learn better the next time.
If you can measure it, you can improve it.
---
Experimental-first principle
a\ is an experimental optimisation loop. Do not reach for external mathematical optimisers or solvers (e.g. `scipy.optimize`, `cvxpy`, linear/quadratic programming solvers, evolutionary algorithm libraries, Bayesian optimisation frameworks, or any other off-the-shelf optimisation package) as a shortcut to improving the artifact. The value of a\ is in the structured explore-evaluate-reflect cycle, not in delegating the search to a solver.
If at any point during onboarding, pre-run analysis, or execution you believe the problem is well-suited to a closed-form or mathematical optimisation approach, you must ask the user first before pursuing it. Present it as an alternative:
"This problem looks like it could be approached with a mathematical optimiser
(e.g. [specific method]). Would you like me to try that instead of running the
experimental loop, or would you prefer to proceed with a\*?"
Do not silently install, import, or invoke an external optimiser. Do not reframe the a\ loop as a wrapper around a solver. If the user explicitly opts for a mathematical approach, that is a different workflow — not an a\ run.
---
Concepts
Before running, ensure you understand these terms precisely:
| Term | Meaning |
|---|---|
| Step | One execution with one parameter set. Atomic unit of work. |
| Play | A named bundle of parameters that move together (optional; disable with plays: false). |
| Lap | A set of steps sharing the same parameter family. Establishes statistical confidence in a direction. |
| Round | A set of laps. Ends with a mandatory reflection: worth pursuing? ask user? pivot? |
| Run | One user-initiated process. Lasts until budget is exhausted or goal is met. |
| Track | One independently verifiable sub-goal. Has its own verifier and ratchet. |
| Disposition | A learned prior on how to approach a (problem class, action intent) pair. Stored in long-term memory; conditions all significant actions. |
---
Runtime capability contract
Before Phase 1, detect the host runtime's capabilities and map them onto the abstract adapter contract in references/runtime-capabilities.md.
Use abstract capabilities first:
structured_choicefor bounded approvalsfreeform_inputfor open-ended elicitationfile_presentation/local_htmlfor rubric builder and visualisersubprocessfor external-tool verifiers and render scriptspause_resumefor human gates and round escalations
Claude-specific tools are examples of adapters, not the specification:
- Claude Code:
ask_user+ shell + browser/file paths - Claude.ai: structured chat +
present_files
If a capability is missing, follow the fallback policy in references/runtime-capabilities.md before onboarding the mission.
Concrete runtime profiles and adapters live in:
runtime-profiles/claude-code.jsonruntime-profiles/codex.jsonruntime-profiles/gemini.jsonruntime-profiles/claude-ai.jsonruntime-profiles/pi.jsonruntime-profiles/chat-only.jsonruntime-profiles/template.jsonreferences/adapter-claude-code.mdreferences/adapter-codex.mdreferences/adapter-gemini.mdreferences/adapter-claude-ai.mdreferences/adapter-pi.mdreferences/adapter-chat-only.mdreferences/adapter-template.mdscripts/runtime_profile.py
Before detailed verifier/rubric work, check that the active runtime can support the proposed mission. Use scripts/runtime_profile.py check-mission with the current runtime profile and planned verifier types. If it fails, stop and reconfigure before proceeding.
---
Phase 1: Onboarding
Do not begin execution until onboarding is complete and the user has approved the mission.
Onboarding is an interactive dialogue, not a monologue. At every decision point you must stop and ask the user rather than inferring and proceeding. Use the host runtime's structured_choice capability for bounded decisions; in Claude Code this maps to ask_user. Use open prose questions for genuinely open-ended inputs (e.g. goal description, rubric wording).
The mandatory user-confirmation checkpoints are:
1. Goal decomposition confirmed — present inferred tracks as choices; user approves, removes, or adds before proceeding 2. Required vs preferred — for each track, explicitly ask; do not infer 3. Verifier type per track — present options; user selects 4. Hard constraints confirmed — present inferred list; user amends 5. Budget — present three concrete options; user selects 6. Plays — enabled/disabled, and approval of proposed bundles 7. Final mission confirmation — full summary; explicit go/no-go before any step runs
Never skip a checkpoint. If the user's initial message contained enough information to pre-populate an answer, present it as a pre-selected option and ask them to confirm or change it. Do not silently accept it.
Rubric builder: When configuring LLM judge tracks (onboarding checkpoint 2+), surface the bundled rubric builder through the runtime's local_html or file_presentation capability so the user can describe score anchors interactively and get a generated rubric they can edit and confirm:
# Claude Code / terminal
open assets/rubric-builder.html # macOS
xdg-open assets/rubric-builder.html # Linux
start assets/rubric-builder.html # WindowsIf running in Claude.ai, use present_files on assets/rubric-builder.html instead. If the runtime cannot surface local HTML, fall back to manual rubric elicitation as defined in references/runtime-capabilities.md. The user exports a tracks.md from the tool; load that as the confirmed track configuration. Only fall back to manual elicitation for tracks the tool did not cover (external_tool, deterministic, human_gate types do not need a rubric).
Read references/onboarding.md for the full dialogue flow, question wording, and decision trees at each checkpoint. Read references/runtime-capabilities.md before adapting this flow to a non-Claude host.
Rubric builder UI: When Phase B (verifier elicitation) reaches an llm_judge or hybrid track, present assets/rubric-builder.html to the user before configuring that track. The builder calls Claude to generate the rubric from the user's anchor descriptions, lets them review and edit it inline, and exports a tracks.md file you can use directly. Tell the user:
"I'm opening the rubric builder for the [track name] track. Describe the score
anchors, and it will draft the rubric for you to review and confirm."
After the user exports tracks.md from the builder, read it and use it as the track configuration. Do not re-elicit rubrics that are already confirmed there.
The onboarding produces four documents, all stored in the run directory:
mission.md
GOAL: [plain language description of success]
ARTIFACT: [what is being mutated and where it lives]
PLAYS: enabled | disabled
BUDGET: [strategy + ceiling — see references/budgeting.md]
STOPPING_CRITERIA: [score threshold | plateau_n | budget_exhausted]
REPORTING: [what the final report must contain]tracks.md
One block per track. See Verification taxonomy below for verifier types.
TRACK: <name>
required: true | false
weight: 0.0–1.0 (weights across non-required tracks must sum to 1.0)
verifier: <see taxonomy>
threshold: <pass/fail cutoff or target score>
ratchet: independent | composite (default: independent)constraints.md
HARD: [list — violations cause immediate step rejection before scoring]
SOFT: [list — passed to LLM judge as weighting hints]plays.md (if enabled)
PLAY: <name>
parameters: [list of (param, from, to)]
hypothesis: [why these move together]
tracks_targeted: [list]
atomic_fallback: true | false---
Verification taxonomy
This is the core of the rubric system. Every track must declare one of the following verifier types. Read references/verification.md for full configuration details and examples for each type.
1. Deterministic programmatic
A function, script, or expression that produces a binary pass/fail or a bounded score with no randomness. Does not require an LLM call.
Use for: word count, token count, regex match, JSON schema validation, spelling/grammar (rule-based), mathematical constraints, format compliance.
verifier:
type: deterministic
fn: word_count(artifact) <= 400
returns: bool2. External tool (subprocess)
A command-line tool invoked as a subprocess. The tool must be available in the environment; the mission builder checks availability before the run starts. Return code 0 = pass; non-zero = fail (unless score mode is configured).
Common tools and what they verify:
| Domain | Tool | What it checks |
|---|---|---|
| Python typing | pyright, mypy | Static type correctness |
| Python tests | pytest | Test suite passage |
| TypeScript | tsc --noEmit | Type correctness |
| JavaScript | eslint | Lint rules |
| Accessibility | axe-cli, pa11y | WCAG compliance |
| Web performance | lighthouse-ci | Perf / a11y / SEO scores |
| CSS | stylelint | Style rule compliance |
| Markdown | markdownlint | Document structure |
| OpenAPI | vacuum | API spec validity |
| Prose | vale | Style guide adherence |
| Security | bandit, semgrep | Vulnerability patterns |
| Build | tsc, cargo check | Compilation success |
| Inference perf | aitune | Model latency, throughput, memory (see AITune delegation below) |
verifier:
type: external_tool
command: pyright src/handler.py --outputjson
parse_output: json_error_count # or: exit_code, json_path, regex_capture
returns: score # 1.0 - (errors / lines)
required_env: [python, pyright]If a required tool is absent, the mission builder must either guide the user to install it, or replace the track with an LLM judge approximation (lower confidence; flagged in the run report).
3. LLM judge
A structured LLM call with a fixed rubric. The rubric is immutable for the duration of the run — it must not be modified by any agent. Temperature should be ≤ 0.2. For high-stakes tracks, use an ensemble of two independent judge calls and average.
verifier:
type: llm_judge
rubric: |
Score 0.0–1.0. Evaluate the documentation quality of the provided function.
0.8+ requires: accurate parameter descriptions, return type explanation,
at least one usage example, and a description of error conditions.
Penalise: missing examples, vague descriptions, undocumented exceptions.
temperature: 0.1
ensemble: 2
returns: scoreThe judge must also return a rationale string of 1–3 sentences. This is written to short-term memory and feeds the round reflection.
4. Hybrid
A deterministic verifier AND an LLM judge, aggregated.
verifier:
type: hybrid
deterministic: entity_checker(artifact, source)
llm_judge: factual_consistency_rubric
aggregation: min | mean | weighted
returns: scoreUse min aggregation when both components are required to pass independently (i.e., a high LLM score cannot compensate for a failed deterministic check).
5. Human gate
Pauses the run and surfaces the artifact to the user for approval. Use sparingly; counts against budget. Appropriate when a track cannot be reliably automated (e.g., brand approval, legal sign-off, aesthetic judgement with no proxy metric).
verifier:
type: human_gate
prompt: "Does this copy meet the brand voice guidelines? Score 0–10."
timeout_action: skip | block | auto_score(0.5)Hard constraint enforcement
Hard constraints in constraints.md are checked before any verifier runs. A constraint violation immediately rejects the step with outcome: rejected_constraint and returns zero budget cost for the verifier calls. This is important: do not waste judge budget on an artifact that violates a hard constraint.
---
Inference optimisation and AITune delegation
When the artifact being optimised is a model's inference performance — latency, throughput, GPU memory during serving, or deployment configuration — the mutation step should delegate to AITune rather than blindly experimenting with inference configurations through the a\* loop alone.
Why this matters: Inference optimisation has a structured search space (backends, precision levels, compilation strategies) that AITune already navigates well. a\*'s value here is in wrapping AITune with multi-dimensional quality constraints (accuracy preservation, latency targets, memory budgets) and the reflect-and-learn cycle — not in reinventing AITune's internal search.
Detection during onboarding: If the user's goal involves model serving speed, inference latency, throughput, quantization for deployment, or GPU-accelerated inference, flag this as an inference optimisation mission during Phase 1 and suggest AITune delegation. Present it as an option:
"This looks like an inference optimisation problem. I can delegate the
low-level tuning (backend selection, quantization, graph optimisation) to
AITune while keeping a\*'s quality tracking and learning loop around it.
Would you like to use AITune for the inference tuning?"
If the user agrees, read references/aitune.md for the full delegation protocol, including track templates, play design patterns, and correctness validation setup. The key architectural point: each a\ step invokes AITune with a parameter set; a\ evaluates the result against all tracks; the ratchet and reflection machinery works as normal.
If AITune is not installed, offer the install command during Phase 2 tool checks:
pip install --extra-index-url https://pypi.nvidia.com aitune---
Phase 2: Pre-run preparation
Before the first round begins:
1. Check tool availability. For every external_tool verifier, run a dry-fire check (pyright --version, axe-cli --version, etc.). Report any missing tools to the user and resolve before proceeding.
2. Baseline run. Execute one step with the unmodified artifact. Record baseline scores for all tracks. This is step r0_l0_s0 and is never ratcheted.
3. Query disposition library. Retrieve relevant dispositions for this problem class. Surface them to the user briefly: "Based on previous runs, I know X about this class of problem."
4. Propose initial plays (if enabled). Present to user for approval or amendment.
5. Confirm mission. Show the user the complete mission.md, tracks.md, and constraints.md before any optimisation steps run. Do not proceed without explicit approval.
---
Phase 3: Execution loop
Progress visualisation
VISUALIZATION POLICY: USE THE TEMPLATE — DO NOT IMPROVISE
A prototype progress chart lives at assets/inline-progress-chart.html. Use it as a template — do not invent your own visualisation from scratch, do not generate random dashboards, and do not create standalone HTML files that open in a browser. Claude Code supports inline HTML visuals in chat; use that capability.
To render the chart after each step: 1. Read assets/inline-progress-chart.html as a template 2. Replace the sample STEPS, REFLECTIONS, and BUDGET data with actual run data from step_log.jsonl, reflections.jsonl, and progress.json 3. Emit the resulting HTML inline in the conversation
Re-render after every step so the user always sees current state.
The chart has three visual components:
1. Composite score chart — staircase (step-style) curve for the winning trajectory (kept steps), with ghost dots for reverted alternatives. Each ghost dot connects back to its most recent kept ancestor via a pale bezier curve, showing what was tried and rejected. Reverted scores are labelled so the user sees what alternatives produced.
2. Branch genealogy — compact per-round row of kept/reverted dots grouped by lap, with the best score for the round.
3. Round reflections — structured cards for each round reflection, showing the three key questions (worth pursuing / ask user / pivot), reasoning, limiting track, budget remaining, and pace projection. Do not dump raw reflection text into the conversation — always render it through the template's structured card format.
Do not add per-track breakdowns, heatmaps, detailed step tables, or any other visual elaboration beyond what the template provides. If the user wants more detail, they can ask.
Data files
The run directory contains machine-readable state for external consumption. Keep these current but do not render them as visuals — they exist for programmatic access, not for display.
`runs/<run_id>/step_log.jsonl` — one JSON record per line, one per step. Same schema as the step record below. Appended after each step.
`runs/<run_id>/tracks.json` — array of track definitions:
[{ "id": "type_correctness", "label": "type_correctness",
"required": true, "weight": null }]Written once at run start from the confirmed tracks.md.
`runs/<run_id>/reflections.jsonl` — one JSON record per line per round reflection. Appended after each round.
`runs/<run_id>/mission.json` — run metadata:
{ "run_id": "run_20260324", "budget": { "total_tokens": 120000 } }Written once at run start.
`runs/<run_id>/progress.json` — machine-readable snapshot of current state. Updated after every step. See schemas/progress.schema.json for the full JSON Schema.
{
"run_id": "run_20260324",
"status": "running",
"updated_at": "2026-03-24T14:23:00Z",
"baseline": { "composite": 0.45, "tracks": { "type_correctness": 0.80 } },
"current": { "composite": 0.82, "tracks": { "type_correctness": 0.95 }, "step_id": "r2_l1_s4" },
"delta": { "composite": 0.37, "tracks": { "type_correctness": 0.15 } },
"budget": { "total_steps": 80, "used_steps": 34, "remaining_pct": 57.5 },
"rounds_completed": 2,
"steps_completed": 34,
"steps_kept": 18,
"momentum": "exploiting_successfully",
"limiting_track": "docstring_quality",
"last_reflection": { "worth_pursuing": "yes", "pivot": "none", "pace_projection": 0.89 }
}Step execution
For each step:
1. Apply hard constraint check → reject immediately if violated
2. Execute the artifact mutation (play or atomic)
3. Run all track verifiers in dependency order (required tracks first)
4. Compute composite score: Σ(weight_i × score_i), gated by required tracks
5. Apply per-track ratchet:
- independent ratchet: each track keeps/reverts its own parameter changes
- composite ratchet: keep only if overall composite improves
6. Write step record to short-term memoryStep record schema:
id: run_03_r2_l1_s4
parameters: {param: value, ...}
play: play_name | null
track_scores: {track_name: score, ...}
composite: float
judge_notes: {track_name: rationale, ...}
constraints: passed | rejected (+ which constraint)
cost: {tokens: n, wall_s: n}
outcome: keep | revert | partial_keep | rejected_constraintLap completion
When all steps in a lap are done:
score_distribution: {mean, std, max, min}
verdict: promising | exhausted | noisy
- promising: mean score above lap threshold and improving
- exhausted: score has plateaued across steps with low variance
- noisy: high variance; more steps needed to confirm
hypothesis_result: confirmed | partial | refuted
budget_used: {tokens, steps}If verdict is noisy and budget allows, the lap may request additional steps before closing. The budget controller gates this.
Round reflection
Every round ends with a recorded reflection, without exception. The reflection is not optional even when nothing changes. A "no change" record is valuable: it documents that the question was considered.
ROUND REFLECTION
round_id:
laps_completed:
score_trajectory: [list of lap means]
track_trajectories: {track: [scores]} ← per-track view
limiting_track: <which track is the current ceiling>
QUESTION 1 — Worth pursuing?
assessment: yes | no | uncertain
reasoning: [2–4 sentences]
QUESTION 2 — Ask the user?
trigger: none | stuck | diverging_tracks | pace_risk | constraint_conflict
message: [specific, actionable question if triggered — not "we're stuck"]
QUESTION 3 — Pivot?
decision: none | minor | major | abandon
reasoning: [required even if none]
next_round_strategy: [what changes, if anything]
budget_remaining: %
pace_projection: expected score at budget exhaustionAsk-user triggers (automatic):
- Score has not improved across two consecutive rounds
- Two or more tracks are diverging (improving one reliably hurts another)
- Budget is 50% consumed with < 30% of target score achieved
- All laps in round returned
exhausted - A required track is consistently failing with no clear fix
When asking the user, be specific. Not "we're stuck" but:
"Improving documentation quality (track score: 0.74) consistently reduces
type correctness (track score drops from 1.0 to 0.91) because the added
comments confuse pyright's inference. Should I relax the type correctness
threshold, or is that a hard requirement?"
---
Phase 4: Memory and learning
Read references/memory.md for the full memory architecture.
Short-term memory (within run)
- Full step log
- Hypothesis stack with provenance
- Track trajectories
- Score momentum signal
- Failed hypotheses with failure modes (not just "failed" — why)
Long-term memory (disposition library)
Keyed on (problem_class, action_intent). Each entry is a natural-language conditioned prior on how to approach this class of action on this class of problem.
The memory agent runs a consolidation pass at the end of each round:
- Does any disposition need updating based on this round's evidence?
- Did a disposition prove wrong? Flag it with a negative exemplar.
- Should a problem class be forked? (Two sub-classes behaving differently)
The memory agent may run a meta-research step only when the mission has explicitly enabled external research. If research is disabled, skip this path and continue using only local evidence, run history, user guidance, and bundled references.
If enabled and disposition confidence is below threshold for an upcoming action class: 1. Prefer local references, bundled docs, and tool help before any network fetch 2. If external lookup is still justified, prefer vendor docs or a mission allowlist over the open web 3. Do not send artifact contents, source code, secrets, or proprietary identifiers to external services unless the user separately approved that disclosure 4. Synthesise into a candidate disposition 5. Apply on the next action 6. Observe outcome; confirm or reject the looked-up guidance 7. Record provenance: looked_up_from_web | learned_from_run | user_specified
---
Phase 5: Post-run report
The final report must contain:
- Baseline vs final scores per track
- Score trajectory chart (text-based if no rendering available)
- Round reflection log (all rounds, verbatim)
- What worked (confirmed plays and dispositions)
- What didn't (refuted hypotheses, with failure modes)
- Suggested follow-up directions
- Disposition updates proposed (user can approve or reject)
- Full budget accounting
---
Reference files
Read these when the relevant section is reached:
| File | When to read |
|---|---|
references/onboarding.md | Phase 1 — building mission, tracks, constraints, plays |
references/verification.md | When configuring any track verifier |
references/budgeting.md | When setting or projecting budget |
references/memory.md | When reading/writing disposition library |
references/runtime-capabilities.md | Before adapting a* to any non-Claude runtime |
references/adapter-claude-code.md | When running a* in Claude Code full-support mode |
references/adapter-codex.md | When running a* in Codex full-support mode |
references/adapter-gemini.md | When running a* in Gemini CLI full-support mode |
references/adapter-claude-ai.md | When running a* in Claude.ai reduced-support mode |
references/adapter-pi.md | When running a* in Pi full-support mode |
references/adapter-chat-only.md | To understand the unsupported chat-only boundary |
references/adapter-template.md | When creating a new runtime adapter |
references/aitune.md | When mission involves inference optimisation (latency, throughput, quantization, GPU deployment) |
Assets
Present these to the user at the indicated phase:
| File | Phase | Purpose |
|---|---|---|
assets/rubric-builder.html | Phase 1 — Phase B verifier elicitation | Interactive rubric drafting and confirmation for LLM judge tracks |
assets/inline-progress-chart.html | Phase 3 — after every step | Template for inline progress visualisation. Inject run data and render in chat. Do not invent your own chart — use this. |
Scripts
| File | When to run |
|---|---|
| `scripts/runtime_profile.py list | show |
scripts/runtime_profile.py check-mission ... | After verifier selection, before rubric/budget deepening |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
@import url('https://fonts.googleapis.com/css2?family=Söhne:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap');
:root {
--bg: #2b2b2b;
--surface: #343434;
--surface-raised: #3d3d3d;
--border: rgba(255,255,255,0.06);
--border-subtle: rgba(255,255,255,0.04);
--text: #ececec;
--text-secondary: #a0a0a0;
--text-tertiary: #707070;
--accent: #d4a27a;
--accent-muted: rgba(212,162,122,0.15);
--kept: #7dcea0;
--kept-muted: rgba(125,206,160,0.12);
--kept-subtle: rgba(125,206,160,0.06);
--reverted: #c0756b;
--reverted-muted: rgba(192,117,107,0.10);
--reverted-subtle: rgba(192,117,107,0.05);
--link-color: #85b8d0;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
background: var(--bg);
color: var(--text);
font-family: 'Söhne', -apple-system, 'Segoe UI', sans-serif;
font-size: 13px;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
width: 100%;
max-width: 640px;
}
/* ── Header ──────────────────────────────────────────── */
.head {
display: flex;
align-items: baseline;
justify-content: space-between;
padding: 14px 16px 10px;
border-bottom: 1px solid var(--border);
}
.head-left {
display: flex;
align-items: baseline;
gap: 8px;
}
.head-title {
font-weight: 600;
font-size: 13px;
color: var(--text);
letter-spacing: -0.01em;
}
.head-status {
font-size: 11px;
color: var(--text-tertiary);
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
}
.head-stats {
display: flex;
gap: 16px;
}
.hs {
text-align: right;
line-height: 1.2;
}
.hs-val {
font-family: 'JetBrains Mono', monospace;
font-weight: 500;
font-size: 13px;
color: var(--text);
}
.hs-label {
font-size: 10px;
color: var(--text-tertiary);
letter-spacing: 0.02em;
}
/* ── Chart ───────────────────────────────────────────── */
.section {
padding: 12px 16px 8px;
}
.section-title {
font-size: 10px;
font-weight: 500;
color: var(--text-tertiary);
letter-spacing: 0.04em;
text-transform: uppercase;
margin-bottom: 8px;
}
.chart-frame {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 8px;
padding: 12px 10px 8px;
position: relative;
}
/* ── Budget ──────────────────────────────────────────── */
.budget {
padding: 6px 16px 12px;
display: flex;
align-items: center;
gap: 10px;
}
.budget-label {
font-size: 10px;
color: var(--text-tertiary);
min-width: 40px;
}
.budget-track {
flex: 1;
height: 2px;
background: var(--border);
border-radius: 1px;
overflow: hidden;
}
.budget-fill {
height: 100%;
background: var(--accent);
border-radius: 1px;
opacity: 0.7;
}
.budget-pct {
font-family: 'JetBrains Mono', monospace;
font-size: 10px;
color: var(--text-tertiary);
min-width: 80px;
text-align: right;
}
/* ── Genealogy ───────────────────────────────────────── */
.gen-row {
display: flex;
align-items: center;
gap: 8px;
padding: 3px 0;
}
.gen-round {
font-family: 'JetBrains Mono', monospace;
font-size: 10px;
font-weight: 500;
color: var(--text-secondary);
min-width: 22px;
}
.gen-pips {
display: flex;
gap: 3px;
align-items: center;
}
.gen-pip {
width: 6px;
height: 6px;
border-radius: 50%;
}
.gen-pip.k { background: var(--kept); opacity: 0.8; }
.gen-pip.r { background: var(--reverted); opacity: 0.35; }
.gen-sep {
width: 1px;
height: 8px;
background: var(--border);
margin: 0 1px;
}
.gen-best {
font-family: 'JetBrains Mono', monospace;
font-size: 10px;
font-weight: 500;
color: var(--text-secondary);
margin-left: auto;
}
/* ── Reflections ─────────────────────────────────────── */
.refl {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 8px;
margin-bottom: 6px;
overflow: hidden;
}
.refl-head {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 12px;
border-bottom: 1px solid var(--border-subtle);
}
.refl-round {
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
font-weight: 500;
color: var(--text-secondary);
}
.refl-score {
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
color: var(--kept);
font-weight: 500;
}
.refl-body {
padding: 8px 12px 10px;
}
.refl-grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 6px;
margin-bottom: 8px;
}
.refl-cell {
padding: 5px 8px;
background: var(--surface-raised);
border-radius: 4px;
}
.refl-cell-label {
font-size: 9px;
color: var(--text-tertiary);
letter-spacing: 0.03em;
}
.refl-cell-val {
font-family: 'JetBrains Mono', monospace;
font-size: 12px;
font-weight: 500;
margin-top: 1px;
}
.refl-text {
font-size: 11px;
color: var(--text-secondary);
line-height: 1.55;
padding-left: 8px;
border-left: 2px solid var(--border);
}
.refl-meta {
display: flex;
gap: 12px;
margin-top: 6px;
font-family: 'JetBrains Mono', monospace;
font-size: 9px;
color: var(--text-tertiary);
}
.refl-meta-track { color: var(--accent); }
/* ── Tooltip ─────────────────────────────────────────── */
.tip {
position: absolute;
pointer-events: none;
background: var(--surface-raised);
border: 1px solid var(--border);
border-radius: 6px;
padding: 6px 10px;
font-size: 11px;
line-height: 1.5;
display: none;
z-index: 10;
white-space: nowrap;
font-family: 'JetBrains Mono', monospace;
}
.tip-id { color: var(--text-tertiary); font-size: 10px; }
.tip-score { font-weight: 500; }
.tip-kept { color: var(--kept); }
.tip-rev { color: var(--text-tertiary); }
</style>
</head>
<body>
<div class="head">
<div class="head-left">
<span class="head-title">a* progress</span>
<span class="head-status">running</span>
</div>
<div class="head-stats">
<div class="hs"><div class="hs-val" id="hScore">—</div><div class="hs-label">score</div></div>
<div class="hs"><div class="hs-val" id="hDelta">—</div><div class="hs-label">delta</div></div>
<div class="hs"><div class="hs-val" id="hKept">—</div><div class="hs-label">kept</div></div>
</div>
</div>
<div class="section">
<div class="section-title">Composite score</div>
<div class="chart-frame">
<svg id="chart" width="100%" viewBox="0 0 600 120" preserveAspectRatio="xMidYMid meet"></svg>
<div class="tip" id="tip"></div>
</div>
</div>
<div class="budget">
<span class="budget-label">budget</span>
<div class="budget-track"><div class="budget-fill" id="bFill" style="width:0%"></div></div>
<span class="budget-pct" id="bText">—</span>
</div>
<div class="section">
<div class="section-title">Genealogy</div>
<div id="gen"></div>
</div>
<div class="section">
<div class="section-title">Reflections</div>
<div id="refl"></div>
</div>
<script>
// ── Sample data ───────────────────────────────────────────────────────────
const STEPS = [
{ id:'r0_l0_s0', round:0, lap:0, composite:0.42, outcome:'keep', play:null },
{ id:'r1_l0_s0', round:1, lap:0, composite:0.48, outcome:'keep', play:'tighten_types' },
{ id:'r1_l0_s1', round:1, lap:0, composite:0.39, outcome:'revert', play:'tighten_types' },
{ id:'r1_l0_s2', round:1, lap:0, composite:0.52, outcome:'keep', play:'tighten_types' },
{ id:'r1_l0_s3', round:1, lap:0, composite:0.44, outcome:'revert', play:'tighten_types' },
{ id:'r1_l1_s0', round:1, lap:1, composite:0.55, outcome:'keep', play:'doc_expansion' },
{ id:'r1_l1_s1', round:1, lap:1, composite:0.50, outcome:'revert', play:'doc_expansion' },
{ id:'r1_l1_s2', round:1, lap:1, composite:0.58, outcome:'keep', play:'doc_expansion' },
{ id:'r2_l0_s0', round:2, lap:0, composite:0.61, outcome:'keep', play:'doc_expansion' },
{ id:'r2_l0_s1', round:2, lap:0, composite:0.57, outcome:'revert', play:'doc_expansion' },
{ id:'r2_l0_s2', round:2, lap:0, composite:0.64, outcome:'keep', play:'doc_expansion' },
{ id:'r2_l0_s3', round:2, lap:0, composite:0.60, outcome:'revert', play:'doc_expansion' },
{ id:'r2_l0_s4', round:2, lap:0, composite:0.68, outcome:'keep', play:'doc_expansion' },
{ id:'r2_l1_s0', round:2, lap:1, composite:0.66, outcome:'revert', play:'error_handling' },
{ id:'r2_l1_s1', round:2, lap:1, composite:0.71, outcome:'keep', play:'error_handling' },
{ id:'r2_l1_s2', round:2, lap:1, composite:0.63, outcome:'revert', play:'error_handling' },
{ id:'r2_l1_s3', round:2, lap:1, composite:0.70, outcome:'revert', play:'error_handling' },
{ id:'r2_l1_s4', round:2, lap:1, composite:0.74, outcome:'keep', play:'error_handling' },
{ id:'r3_l0_s0', round:3, lap:0, composite:0.76, outcome:'keep', play:'combined_polish' },
{ id:'r3_l0_s1', round:3, lap:0, composite:0.72, outcome:'revert', play:'combined_polish' },
{ id:'r3_l0_s2', round:3, lap:0, composite:0.73, outcome:'revert', play:'combined_polish' },
{ id:'r3_l0_s3', round:3, lap:0, composite:0.78, outcome:'keep', play:'combined_polish' },
{ id:'r3_l0_s4', round:3, lap:0, composite:0.75, outcome:'revert', play:'combined_polish' },
{ id:'r3_l0_s5', round:3, lap:0, composite:0.80, outcome:'keep', play:'combined_polish' },
{ id:'r3_l0_s6', round:3, lap:0, composite:0.77, outcome:'revert', play:'combined_polish' },
{ id:'r3_l0_s7', round:3, lap:0, composite:0.82, outcome:'keep', play:'combined_polish' },
];
const REFLECTIONS = [
{ round:1, score_at_end:0.58, worth_pursuing:'yes', ask_user:false, pivot:'none',
reasoning:'Type tightening yielded moderate gains (0.42 → 0.52) but doc expansion was more effective (→ 0.58). Next round should focus on documentation while maintaining type discipline.',
limiting_track:'docstring_quality', budget_remaining_pct:78, pace_projection:0.85 },
{ round:2, score_at_end:0.74, worth_pursuing:'yes', ask_user:false, pivot:'minor',
reasoning:'Strong progress this round (+0.16). Doc expansion hitting diminishing returns; error handling opened a new improvement vector. Combining both next round.',
limiting_track:'error_coverage', budget_remaining_pct:55, pace_projection:0.88 },
{ round:3, score_at_end:0.82, worth_pursuing:'yes', ask_user:false, pivot:'none',
reasoning:'Combined polish play effective. 8 steps with 4 kept — 50% hit rate on a challenging frontier. Trajectory suggests 0.85+ achievable within remaining budget.',
limiting_track:'docstring_quality', budget_remaining_pct:33, pace_projection:0.89 },
];
const BUDGET = { total_steps:80, used_steps:STEPS.length };
// ── Render ────────────────────────────────────────────────────────────────
document.addEventListener('DOMContentLoaded', () => {
const kept = STEPS.filter(s => s.outcome === 'keep');
const last = kept[kept.length - 1];
const base = STEPS[0];
document.getElementById('hScore').textContent = last ? last.composite.toFixed(2) : '—';
document.getElementById('hKept').textContent = kept.length + '/' + STEPS.length;
if (last && base) {
const d = last.composite - base.composite;
document.getElementById('hDelta').textContent = (d >= 0 ? '+' : '') + d.toFixed(2);
document.getElementById('hDelta').style.color = d >= 0 ? '#7dcea0' : '#c0756b';
}
const pct = Math.min(100, (BUDGET.used_steps / BUDGET.total_steps) * 100);
document.getElementById('bFill').style.width = pct + '%';
document.getElementById('bText').textContent = BUDGET.used_steps + ' / ' + BUDGET.total_steps + ' steps';
drawChart(STEPS);
drawGen(STEPS);
drawRefl(REFLECTIONS);
});
function drawChart(steps) {
const W = 600, H = 120, PL = 28, PR = 8, PT = 8, PB = 16;
const pW = W - PL - PR, pH = H - PT - PB;
const vals = steps.map(s => s.composite);
const lo = Math.min(...vals) * 0.93;
const hi = Math.min(1, Math.max(...vals) * 1.05);
const rng = hi - lo || 0.01;
const xOf = i => PL + (i / Math.max(steps.length - 1, 1)) * pW;
const yOf = v => PT + pH - ((v - lo) / rng) * pH;
let svg = '';
// Grid — very subtle
for (let t = 0; t <= 4; t++) {
const v = lo + rng * t / 4;
const yy = yOf(v);
svg += `<line x1="${PL}" y1="${yy}" x2="${W-PR}" y2="${yy}" stroke="rgba(255,255,255,0.04)" stroke-width="1"/>`;
svg += `<text x="${PL-4}" y="${yy+3}" text-anchor="end" fill="#707070" font-size="8" font-family="'JetBrains Mono',monospace">${v.toFixed(2)}</text>`;
}
// Round dividers
const rounds = [...new Set(steps.map(s => s.round))];
rounds.forEach(r => {
const idx = steps.findIndex(s => s.round === r);
if (idx <= 0) return;
const rx = xOf(idx);
svg += `<line x1="${rx}" y1="${PT}" x2="${rx}" y2="${H-PB}" stroke="rgba(255,255,255,0.06)" stroke-width="1" stroke-dasharray="2,4"/>`;
});
// Baseline
const bY = yOf(steps[0].composite);
svg += `<line x1="${PL}" y1="${bY}" x2="${W-PR}" y2="${bY}" stroke="rgba(212,162,122,0.2)" stroke-width="1" stroke-dasharray="3,4"/>`;
// Kept-step index
const keptIdx = [];
steps.forEach((s, i) => { if (s.outcome === 'keep') keptIdx.push({ ...s, i }); });
function ancestor(idx) {
let a = null;
for (const k of keptIdx) { if (k.i < idx) a = k; else break; }
return a;
}
// Ghost beziers
steps.forEach((s, i) => {
if (s.outcome === 'keep') return;
const a = ancestor(i);
if (!a) return;
const ax = xOf(a.i), ay = yOf(a.composite);
const gx = xOf(i), gy = yOf(s.composite);
const dx = gx - ax;
svg += `<path d="M${ax},${ay} C${ax+dx*0.5},${ay} ${ax+dx*0.75},${gy} ${gx},${gy}" fill="none" stroke="rgba(192,117,107,0.12)" stroke-width="1"/>`;
});
// Ghost dots
steps.forEach((s, i) => {
if (s.outcome === 'keep') return;
const cx = xOf(i), cy = yOf(s.composite);
svg += `<circle cx="${cx}" cy="${cy}" r="2.5" fill="rgba(192,117,107,0.15)" stroke="rgba(192,117,107,0.25)" stroke-width="0.75" data-idx="${i}"/>`;
});
// Winning staircase
if (keptIdx.length >= 2) {
let d = `M${xOf(keptIdx[0].i)},${yOf(keptIdx[0].composite)}`;
for (let j = 1; j < keptIdx.length; j++) {
const px = xOf(keptIdx[j].i);
const prevY = yOf(keptIdx[j-1].composite);
const curY = yOf(keptIdx[j].composite);
d += ` L${px},${prevY} L${px},${curY}`;
}
const lastX = xOf(keptIdx[keptIdx.length-1].i);
const firstX = xOf(keptIdx[0].i);
const bot = H - PB;
svg += `<defs><linearGradient id="wg" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#7dcea0" stop-opacity="0.08"/>
<stop offset="100%" stop-color="#7dcea0" stop-opacity="0"/>
</linearGradient></defs>`;
svg += `<path d="${d} L${lastX},${bot} L${firstX},${bot} Z" fill="url(#wg)"/>`;
svg += `<path d="${d}" fill="none" stroke="#7dcea0" stroke-width="1.5" stroke-linejoin="miter" opacity="0.7"/>`;
}
// Kept dots
keptIdx.forEach(s => {
svg += `<circle cx="${xOf(s.i)}" cy="${yOf(s.composite)}" r="3" fill="#7dcea0" opacity="0.85" data-idx="${s.i}"/>`;
});
document.getElementById('chart').innerHTML = svg;
// Tooltip
const frame = document.querySelector('.chart-frame');
const tip = document.getElementById('tip');
frame.addEventListener('mousemove', e => {
const svgEl = document.getElementById('chart');
const sr = svgEl.getBoundingClientRect();
const fr = frame.getBoundingClientRect();
const mx = (e.clientX - sr.left) * (W / sr.width);
let best = Infinity, bi = 0;
steps.forEach((s, i) => { const d = Math.abs(xOf(i) - mx); if (d < best) { best = d; bi = i; } });
if (best * (sr.width / W) > 18) { tip.style.display = 'none'; return; }
const s = steps[bi];
const k = s.outcome === 'keep';
tip.innerHTML = `<span class="tip-id">${s.id}</span><br><span class="tip-score ${k?'tip-kept':'tip-rev'}">${s.composite.toFixed(3)}</span> ${k?'kept':'reverted'}${s.play?'<br>'+s.play:''}`;
tip.style.display = 'block';
tip.style.left = Math.min(e.clientX - fr.left + 10, fr.offsetWidth - 140) + 'px';
tip.style.top = (e.clientY - fr.top - 8) + 'px';
});
frame.addEventListener('mouseleave', () => { tip.style.display = 'none'; });
}
function drawGen(steps) {
const el = document.getElementById('gen');
const rounds = [...new Set(steps.map(s => s.round))];
el.innerHTML = rounds.map(r => {
const rs = steps.filter(s => s.round === r);
const laps = [...new Set(rs.map(s => s.lap))];
const kept = rs.filter(s => s.outcome === 'keep');
const best = kept.length ? Math.max(...kept.map(s => s.composite)) : 0;
const pips = laps.map((lap, li) => {
const ls = rs.filter(s => s.lap === lap);
const dots = ls.map(s => `<div class="gen-pip ${s.outcome==='keep'?'k':'r'}" title="${s.id}"></div>`).join('');
return (li > 0 ? '<div class="gen-sep"></div>' : '') + dots;
}).join('');
return `<div class="gen-row">
<span class="gen-round">R${r}</span>
<div class="gen-pips">${pips}</div>
<span class="gen-best">${best.toFixed(2)}</span>
</div>`;
}).join('');
}
function drawRefl(refls) {
const el = document.getElementById('refl');
if (!refls.length) { el.innerHTML = '<div style="font-size:11px;color:#707070">No reflections yet.</div>'; return; }
el.innerHTML = refls.map(r => {
const wCol = r.worth_pursuing === 'yes' ? '#7dcea0' : r.worth_pursuing === 'no' ? '#c0756b' : '#d4a27a';
const aCol = r.ask_user ? '#d4a27a' : '#707070';
const pCol = r.pivot !== 'none' ? '#d4a27a' : '#707070';
return `<div class="refl">
<div class="refl-head">
<span class="refl-round">Round ${r.round}</span>
<span class="refl-score">${(r.score_at_end||0).toFixed(2)}</span>
</div>
<div class="refl-body">
<div class="refl-grid">
<div class="refl-cell">
<div class="refl-cell-label">Worth pursuing</div>
<div class="refl-cell-val" style="color:${wCol}">${r.worth_pursuing}</div>
</div>
<div class="refl-cell">
<div class="refl-cell-label">Ask user</div>
<div class="refl-cell-val" style="color:${aCol}">${r.ask_user?'yes':'no'}</div>
</div>
<div class="refl-cell">
<div class="refl-cell-label">Pivot</div>
<div class="refl-cell-val" style="color:${pCol}">${r.pivot}</div>
</div>
</div>
${r.reasoning ? `<div class="refl-text">${r.reasoning}</div>` : ''}
${r.limiting_track ? `<div class="refl-meta">
<span>limiting: <span class="refl-meta-track">${r.limiting_track}</span></span>
${r.budget_remaining_pct!=null?`<span>budget: ${r.budget_remaining_pct}%</span>`:''}
${r.pace_projection!=null?`<span>pace: ${r.pace_projection.toFixed(2)}</span>`:''}
</div>` : ''}
</div>
</div>`;
}).join('');
}
</script>
</body>
</html>
Chat-only adapter
This file defines the boundary case for running a* in a chat-only host with no file presentation and no subprocess execution.
Use it together with:
references/runtime-capabilities.mdruntime-profiles/chat-only.json
---
Intent
This adapter is intentionally classified as unsupported for full a*.
It exists to make the lower bound explicit:
- what breaks without files
- what breaks without subprocesses
- what can only be salvaged in a narrower prompt-only mode
If a host matches this profile, do not market it as a general a* runtime.
---
Capability summary
Reference profile: runtime-profiles/chat-only.json
Operational consequences:
- onboarding can still happen in prose
- approvals can only be captured via plain chat replies
- no local files can be treated as canonical artifacts
- no HTML tools can be shown
- no external-tool verification can run
---
Why this is unsupported
Full a* depends on:
- canonical mission artifacts
- append-only run logs
- machine-readable progress state
- real tool-based verification when requested
A chat-only host cannot provide those guarantees. Without them:
- auditability collapses
- portability claims become misleading
- external-tool and hybrid tracks become impossible
---
Allowed narrowed mode
If you explicitly want a degraded prompt-optimisation workflow, the host may run only this narrowed mode:
llm_judgetracks- explicit human approvals
- text-only progress summaries
- ephemeral session state only
Even then, call it a narrowed prompt-only mode, not full a*.
---
User-facing runtime announcement
Before onboarding, say this plainly:
"This host is chat-only. I can help with rubric-based iteration in-session,
but I cannot run command-line verifiers, preserve canonical run files, or
provide the full a* audit trail. If you want the full workflow, move to a
subprocess-capable runtime such as Claude Code."
If the user still wants to proceed, require explicit confirmation that they are accepting a narrowed mode.
---
Verifier policy
Supported in narrowed mode:
llm_judgehuman_gate
Conditionally possible:
- trivial deterministic checks that can be reasoned about directly in text
Unsupported:
external_tool- subprocess-backed
hybrid - file-backed progress artifacts
Do not silently replace unsupported tracks. Ask the user whether to: 1. switch runtimes 2. remove the track 3. accept a lower-confidence rubric-based substitute
---
Artifact handling
There are no canonical local artifacts in this profile.
If the user insists on continuing:
- keep mission state as explicitly labeled markdown blocks in chat
- restate the latest canonical block after any change
- warn that persistence ends with the session
This is a compromise, not equivalent functionality.
---
Progress and pause behavior
Human gates can still pause on the next user turn.
Progress reporting is limited to text summaries such as:
Session status
- best candidate so far: version 4
- current judged score: 0.74
- limiting concern: specificity
- remaining budget: estimated manuallyDo not claim progress.json, step_log.jsonl, or visualiser.html exist in this mode unless another system is generating them externally.
---
When to switch runtimes immediately
Switch away from this profile if the user wants:
- pytest, pyright, eslint, lighthouse, or any actual tool output
- durable run logs
- HTML visualiser flows
- reproducible machine-readable artifacts
That is the normal case for full a*.
Claude.ai adapter
This file defines the reduced-support adapter for running a* in Claude.ai. It also applies to Claude Desktop and Claude Mobile when they expose the same inline file-presentation profile.
Use it together with:
references/runtime-capabilities.mdruntime-profiles/claude-ai.json
---
Intent
Claude.ai is a valid reduced-support host for a* when the goal can be evaluated primarily through:
- LLM judge tracks
- deterministic checks the model can reason about directly
- human gates
It is not a full-support host for missions that depend on external CLI verifiers or local subprocess rendering.
---
Capability summary
Reference profile: runtime-profiles/claude-ai.json
Operational consequences:
- structured choices must be done in chat, not with a native chooser widget
- subprocess-based verifier tracks are unavailable
- file-backed logs may need to be represented as canonical in-chat artifacts
- inline visual outputs should be shown in-chat rather than via external browser hops
Memory consequences:
- the checked-in base profile remains conservative and does not claim long-term memory
- the effective session may gain long-term memory only through a real connector or a valid project pack
- Claude's own built-in memory remains advisory only and must not become the system of record
Memory access modes
Claude.ai should use explicit memory modes:
1. connector_backed Preferred. A remote memory connector is configured and reachable. 2. project_pack Fallback. No connector, but project knowledge contains a valid exported memory pack. 3. none Final fallback. The run uses short-term memory only and says so plainly.
direct_backend exists in the global runtime contract but should not be assumed for the base Claude.ai host profile.
---
Phase 0: Runtime announcement
Before onboarding, tell the user exactly what is downgraded:
"I'm running a* in a reduced-support Claude.ai profile. I can do structured
onboarding, rubric-based judging, and human checkpoints, but I cannot run
command-line verifiers such as pytest, pyright, or lighthouse from here.
If you want those tracks, we need a runtime with subprocess access."
If the user requested tool-based verification, stop and ask whether to: 1. switch runtimes 2. replace the track with an LLM judge approximation 3. remove that track
Do not proceed until the user confirms.
---
Phase 1: Onboarding mapping
A. Structured choices
Claude.ai does not assume ask_user, so use explicit bounded prompts in chat.
Pattern:
Choose one:
1. Hard requirement
2. Preference
Reply with the number only, or say "edit" if neither fits.For multi-select:
Select all that apply:
1. Readability
2. Accuracy
3. Concision
4. Something else
Reply with numbers separated by commas.Rules:
- keep options short
- keep the response format explicit
- confirm the parsed selection back to the user before using it
B. Rubric drafting and approval
For each llm_judge or hybrid track: 1. ask for 1.0 / 0.5 / 0.0 anchors in prose 2. ask for explicit failure modes 3. draft the rubric in chat 4. ask a bounded follow-up:
Choose one:
1. Keep this draft and move on
2. Tighten the wording
3. Redo this trackAfter all rubric-bearing tracks are drafted: 1. show the full rubric-bearing section of tracks.md 2. ask for final approval of the inferred rubric set 3. only then lock the rubrics for the run
C. Mission artifacts
When Claude.ai cannot maintain normal local files, preserve these artifacts as canonical named markdown blocks in the conversation:
mission.mdtracks.mdconstraints.mdplays.md
Every time one changes: 1. reprint the full canonical block 2. ask for confirmation if the change affects mission scope or verification
---
Verifier policy in Claude.ai
Supported
llm_judgehuman_gate- narrowly-scoped deterministic checks that can be evaluated directly from the
artifact text without shell access
Unsupported without explicit downgrade
external_toolhybridtracks that require a subprocess component
Downgrade rule
If a track originally wants external_tool or subprocess-backed hybrid:
- explain the limitation
- propose an
llm_judgereplacement only if the user approves - record the downgrade in the mission artifact and final report
- never make the downgrade silently
Recommended wording:
"This runtime can't execute [tool]. I can replace that track with a rubric
judge, but confidence will be lower and the score will no longer be grounded
in the actual tool output."
---
Phase 2: Pre-run preparation
Claude.ai adapter behavior:
- Tool availability checks: skip, because subprocess is unavailable
- Baseline run: still required
- Disposition lookup: optional; only if the effective profile reports a real memory surface
- Mission confirmation: still required, with the full canonical artifacts shown
Add this note to the mission summary when relevant:
"Runtime downgrade: subprocess-backed verification disabled."
Add one memory note too:
"Memory mode: connector_backed. Cross-run learning is active through the configured connector."
"Memory mode: project_pack. Cross-run learning is available with reduced fidelity; manual sync is required after the run."
"Memory mode: none. Long-term memory is unavailable in this session, so a* is running with short-term memory only."
---
Phase 3: Execution loop
Step records
Maintain step records as structured in-chat data if file append is unavailable. At minimum, preserve:
- step id
- parameters or mutation summary
- track scores
- composite score
- rationale notes
- outcome
Progress reporting
Preferred:
- maintain a logical
progress.jsonobject in session state - surface compact progress updates after each round
Fallback text summary format:
Round 2 complete.
Current composite: 0.78 (up from 0.61 baseline)
Best tracks: clarity 0.90, structure 0.84
Limiting track: factual precision 0.55
Budget used: 18 / 40 steps
Decision: worth pursuing, no pivot yetVisualiser
Preferred behavior on Claude.ai/Desktop/Mobile:
- if
runs/<run_id>/visualiser.htmlexists, present it inline withpresent_files - re-present the refreshed file after each round reflection and at completion
- do not redirect the user to an external browser when inline presentation is available
If no rendered visualiser.html exists and the runtime cannot run render_visualiser.py itself:
- present
progress.jsonor equivalent structured state inline - include a compact textual round summary beside it when helpful
Only use text-only updates when inline file presentation is unavailable.
---
Human gates and pause/resume
Claude.ai can support human gates through normal conversation turns.
Pattern: 1. stop mutation 2. present the artifact or relevant excerpt 3. ask for approval or score 4. do not resume until the user responds
Human gate prompts should always specify:
- what changed
- what criterion is being judged
- what response format is expected
---
Final report behavior
The final report must include a runtime-adapter section:
Runtime profile: Claude.ai (reduced support)
Downgraded features:
- external tool verification unavailable
- in-session HTML visualiser rendering unavailable
Tracks affected:
- type correctness: replaced with LLM judgeIf no downgrades were used, state that explicitly. If project-pack mode was used, also say that updated pack files need manual sync back into project knowledge or GitHub.
---
When not to use this adapter
Do not use the Claude.ai adapter when:
- the mission depends on pytest, pyright, eslint, lighthouse, or any real tool output
- the user needs append-only run logs written locally
- the run depends on generating local HTML artifacts during execution and no other runtime can render them
In those cases, move the run to a subprocess-capable host such as Claude Code.
Claude Code adapter
This file defines the full-support adapter for running a* in Claude Code.
Use it together with:
references/runtime-capabilities.mdruntime-profiles/claude-code.json
---
Intent
Claude Code is the reference full-support host for a*.
It supports the complete workflow:
- structured onboarding
- local file-backed mission artifacts
- subprocess verifiers
- rendered local HTML artifacts
- human gates with pause/resume behavior
This is the adapter to copy when implementing a* in another tool with comparable capabilities.
---
Capability summary
Reference profile: runtime-profiles/claude-code.json
Operational consequences:
- bounded decisions should use
ask_user - external-tool verifiers are available through shell/subprocess execution
- mission and run artifacts should be persisted as real files
- the rendered visualiser can be opened in the local browser when useful
---
Phase 0: Runtime announcement
Before onboarding, state the active runtime profile briefly:
"I'm running a* in the Claude Code full-support profile, so I can use
structured approval steps, local run artifacts, command-line verifiers,
and the rendered visualiser."
If the environment is missing a required CLI tool for a requested verifier, surface that as a tool availability issue, not as a runtime downgrade.
---
Phase 1: Onboarding mapping
A. Structured choices
Use ask_user for every bounded checkpoint.
Required checkpoints:
- track selection
- required vs preferred
- verifier type selection
- hard constraint confirmation
- budget selection
- plays enabled/disabled and play approval
- final mission approval
Rules:
- prefill inferred answers as defaults when possible
- never infer and continue without confirmation
- if the user chooses "other", loop back and reconfirm the updated set
B. Freeform input
Use normal chat turns for:
- open goal description
- rubric anchor descriptions
- soft constraints
- custom budget ceilings
When converting freeform input into canonical artifacts, reflect it back before committing the file.
C. Rubric drafting and approval
For each llm_judge or hybrid track: 1. ask for the 1.0, 0.5, and 0.0 anchors in normal chat 2. ask what explicit penalties should reduce the score 3. draft the rubric in chat 4. use ask_user to decide whether to keep it, tighten it, or redo that track
After all rubric-bearing tracks have provisional drafts: 1. show the rubric-bearing portion of tracks.md 2. use ask_user for final rubric approval 3. do not lock the rubrics until the user approves the full inferred set
D. Mission artifacts
Persist the following as real files in the run directory:
mission.mdtracks.mdconstraints.mdplays.md
Rules:
- regenerate the full artifact on each confirmed update
- do not keep hidden in-memory variants that differ from the files
- use the file versions as the source of truth during execution
---
Verifier policy in Claude Code
Supported
deterministicexternal_toolllm_judgehybridhuman_gate
Tool availability rule
For every external_tool verifier: 1. run a dry-fire check such as tool --version 2. if missing, tell the user exactly which tool is unavailable 3. ask whether to install it, replace the track, or remove the track
Do not silently replace a missing tool with an LLM judge.
Hybrid tracks
If both tool and judge components are available, keep both. Use the aggregation mode defined in the track configuration.
---
Phase 2: Pre-run preparation
Claude Code adapter behavior:
- Tool availability checks: required for all
external_toolverifiers - Baseline run: required
- Disposition lookup: use if available in the host setup
- Mission confirmation: required, based on the persisted run artifacts
Before execution begins, show the user a concise summary of:
- approved tracks
- required tools
- budget
- stopping criteria
---
Phase 3: Execution loop
Step records
Persist step records to runs/<run_id>/step_log.jsonl.
Each record must include:
- step id
- parameters
- play name or null
- per-track scores
- composite score
- rationale/judge notes
- constraint outcome
- budget cost
- keep/revert verdict
Progress reporting
Maintain:
runs/<run_id>/progress.jsonruns/<run_id>/reflections.jsonlruns/<run_id>/tracks.jsonruns/<run_id>/mission.json
Round updates to the user should reference these artifacts rather than inventing a separate reporting format.
Visualiser
Preferred path:
python scripts/render_visualiser.py runs/<run_id> --open --status runningRe-render after each round reflection and on completion:
python scripts/render_visualiser.py runs/<run_id> --status completedIf browser opening fails, keep rendering visualiser.html and tell the user the file path to open manually. The render step is still required.
---
Human gates and pause/resume
Claude Code supports human gates by pausing autonomous progress until the user responds in the next turn.
Pattern: 1. stop mutation after the current checkpoint 2. present the artifact or file path under review 3. ask a bounded approval/scoring question 4. do not continue until the user replies
Human gates should cite:
- the track being judged
- the artifact under review
- the response format expected
---
Final report behavior
The final report should include:
- baseline vs final scores
- track-by-track outcome
- reflection log summary
- approved disposition updates
- budget accounting
Runtime section:
Runtime profile: Claude Code (full support)
Tool availability issues encountered:
- none
Runtime downgrades:
- noneIf a requested tool was unavailable and the user approved a replacement, that belongs under tool availability issues, not under runtime capability.
---
When not to use this adapter
Do not use the Claude Code adapter only if the local environment itself blocks required capabilities for the mission, for example:
- the needed verifier tools are not installed and cannot be added
- the filesystem is unavailable for run artifact persistence
- browser/file presentation is blocked and the mission depends on HTML tools
In those cases, adapt the mission or switch environments before starting.
Codex adapter
This file defines the full-support adapter for running a* in OpenAI Codex CLI-style coding hosts with shell access and file-backed workspace state.
Use it together with:
references/runtime-capabilities.mdruntime-profiles/codex.json
---
Intent
OpenAI Codex CLI is a valid full-support host for a* when it has:
- workspace file access
- subprocess execution
- normal pause/resume conversation flow
It differs from Claude Code mainly in interaction ergonomics, not in core capability coverage.
---
Capability summary
Reference profile: runtime-profiles/codex.json
Operational consequences:
- bounded approvals should use explicit numbered or labeled prompts in chat
- external-tool verifiers are available through shell/subprocess execution
- mission and run artifacts should be persisted as real files
- rendered HTML artifacts should be surfaced by file path or external open flow
---
Phase 0: Runtime announcement
Before onboarding, state the active profile briefly:
"I'm running a* in the Codex full-support profile. I can use file-backed run
artifacts and command-line verifiers, but bounded approvals happen through
explicit chat prompts rather than a native chooser UI."
---
Phase 1: Onboarding mapping
A. Structured choices
Use bounded chat prompts for every checkpoint that needs explicit approval.
Pattern:
Choose one:
1. Hard requirement
2. Preference
Reply with the number only, or say "edit" if neither fits.Rules:
- keep options short and mutually distinct
- restate the parsed answer before writing canonical artifacts
- never infer a choice from surrounding prose without confirmation
B. Freeform input
Use normal chat turns for:
- mission description
- evaluation criteria
- soft constraints
- custom budgets
Reflect transformed prose back to the user before locking it into mission files.
C. Mission artifacts
Persist the following as real files in the run directory:
mission.mdtracks.mdconstraints.mdplays.md
Use those files as the source of truth during execution.
---
Verifier policy in Codex
Supported:
deterministicexternal_toolllm_judgehybridhuman_gate
Tool availability rule: 1. dry-run each requested external verifier before execution 2. if a tool is missing, surface it as an environment/tooling issue 3. ask whether to install it, replace the track, or remove the track
Do not silently downgrade a missing tool-backed track.
---
Execution behavior
- Persist step records and progress artifacts as normal files under
runs/<run_id>/ - Re-render
visualiser.htmlafter round reflections and on completion - Present review artifacts by path when inline rendering is unavailable
- Pause on human gates until the user responds in the next turn
---
When to downgrade
Downgrade only when the live Codex environment is missing one of the declared capabilities, such as disabled shell access or blocked filesystem writes. Treat those as environment-specific constraints, not as changes to the profile contract itself.
Gemini CLI adapter
This file defines the full-support adapter for running a* in Gemini CLI-style hosts with shell access and file-backed workspace state.
Use it together with:
references/runtime-capabilities.mdruntime-profiles/gemini.json
---
Intent
Gemini CLI is a valid full-support host for a* when it exposes:
- workspace file access
- subprocess execution
- conversational pause/resume behavior
The main ergonomic limitation relative to Claude Code is the lack of a native structured chooser widget.
---
Capability summary
Reference profile: runtime-profiles/gemini.json
Operational consequences:
- bounded approvals should use explicit numbered or labeled prompts in chat
- external-tool verifiers are available through shell/subprocess execution
- mission and run artifacts should be persisted as real files
- rendered HTML artifacts should be surfaced by file path or external open flow
---
Phase 0: Runtime announcement
Before onboarding, state the active profile briefly:
"I'm running a* in the Gemini CLI full-support profile. I can use file-backed
artifacts and command-line verifiers, but approvals happen through explicit
chat prompts rather than a native chooser UI."
---
Phase 1: Onboarding mapping
A. Structured choices
Use bounded chat prompts for all required approvals.
Pattern:
Choose one:
1. Keep this track required
2. Downgrade it to preferred
3. Remove it
Reply with the number only.Rules:
- keep the response format explicit
- confirm the parsed answer before updating mission files
- do not continue on ambiguous replies
B. Freeform input
Use normal chat turns for:
- goal description
- evaluation criteria
- constraints
- budget negotiation
Reflect interpreted freeform input back before committing canonical artifacts.
C. Mission artifacts
Persist canonical mission files in the workspace:
mission.mdtracks.mdconstraints.mdplays.md
Use the persisted files, not hidden session state, as the run source of truth.
---
Verifier policy in Gemini CLI
Supported:
deterministicexternal_toolllm_judgehybridhuman_gate
Tool availability rule: 1. check each requested external tool before the run 2. surface missing tools explicitly 3. require user confirmation before replacing or removing any affected track
---
Execution behavior
- Persist
step_log.jsonl,progress.json,reflections.jsonl,tracks.json, andmission.json - Re-render
visualiser.htmlafter each round reflection and on completion - Present artifacts by path when inline rendering is unavailable
- Pause cleanly for human gates and wait for the next user reply
---
When to downgrade
Downgrade only when the concrete Gemini host lacks one of the required runtime capabilities, such as disabled shell access or restricted workspace writes. In that case, record the downgrade explicitly in the mission summary and final report.
Pi adapter
This file defines the full-support adapter for running a* in the Pi coding agent.
Use it together with:
references/runtime-capabilities.mdruntime-profiles/pi.json
---
Intent
Pi coding agent is a valid full-support host for a* when used in its normal coding-agent form with built-in file tools and bash.
It supports the core a* workflow through:
- file-backed workspace operations
- subprocess-backed verification via
bash - persisted session state
- skills and extensions for runtime customization
---
Capability summary
Reference profile: runtime-profiles/pi.json
Operational consequences:
- bounded approvals should use explicit numbered prompts in chat unless an
installed extension provides richer structured UI
- canonical mission and run artifacts can live as real files in the workspace
- external-tool verifiers can run through
bash - HTML artifacts are generally surfaced externally by path or export flow
---
Phase 0: Runtime announcement
Before onboarding, say this plainly:
"I'm running a* in the Pi full-support profile. I can read and modify files,
run command-line verifiers through bash, and persist run artifacts. Approval
checkpoints happen through explicit chat prompts unless the current Pi setup
has a richer UI extension installed."
---
Phase 1: Onboarding mapping
A. Structured choices
Use bounded chat prompts for required approvals unless a Pi extension provides a dedicated selector UI.
Rules:
- keep the response format explicit
- confirm parsed selections before updating canonical artifacts
- never infer approval from freeform prose
---
B. Mission artifacts
Persist canonical files in the workspace or run directory:
mission.mdtracks.mdconstraints.mdplays.md
Use those files, not hidden session state, as the source of truth.
---
Verifier policy in Pi
Supported:
deterministicexternal_toolllm_judgehybridhuman_gate
Tool availability rule: 1. verify requested tools before execution 2. surface missing tools explicitly 3. require user confirmation before downgrading or removing tracks
---
Execution behavior
- persist run artifacts under
runs/<run_id>/ - use
bashfor tool-backed verification and visualiser rendering - surface artifacts by path or export flow when the user needs to inspect them
- pause cleanly for human gates and resume on the next user turn
---
Note on extensions and skills
Pi has official support for skills, extensions, and pi packages, but I did not find a published Pi creator skill by that exact name. If you want a scaffold specifically for Pi extensions or packages, that should likely be added as a separate adapter reference or skill rather than inferred here.
Adapter template
Use this file when porting a* to a new host runtime.
Pair it with:
references/runtime-capabilities.mdruntime-profiles/template.json
---
Deliverables
Every new adapter should add three things:
1. A runtime profile file in runtime-profiles/ 2. A runtime-specific reference document in references/ 3. A README/SKILL reference so the adapter is discoverable
---
Build sequence
1. Fill in the runtime profile
Start from runtime-profiles/template.json.
You must answer:
- Can the host do bounded user choices?
- Can it capture freeform answers?
- Can it present files?
- Can it render or open local HTML?
- Can it run subprocesses?
- Can it truly pause and resume?
- Can it persist run artifacts?
- Can it store cross-run memory?
Do not round capabilities up. Optimistic profiles create bad missions.
2. Classify support level
Use the rules in references/runtime-capabilities.md:
- full support
- reduced support
- unsupported
Write that classification at the top of the adapter doc.
3. Define onboarding mappings
For each onboarding checkpoint, specify:
- the host primitive used
- the exact fallback if the primitive is missing
- how explicit confirmation is captured
At minimum, cover:
- track selection
- required vs preferred
- verifier type selection
- budget selection
- final mission approval
4. Define verifier policy
List verifier types under:
- fully supported
- supported with downgrade
- unsupported
For every downgraded verifier type, define:
- the user-facing warning
- the replacement behavior
- where the downgrade is recorded
5. Define artifact handling
Explain how the runtime handles:
mission.mdtracks.mdconstraints.mdplays.mdstep_log.jsonlreflections.jsonlprogress.json
If true files are unavailable, define the in-session canonical representation.
6. Define progress and pause behavior
Specify:
- how round progress is shown
- whether HTML visualisation is available
- how human gates pause the run
- how the run resumes
7. Define final-report disclosures
Every adapter must state:
- runtime name
- support level
- downgraded capabilities used in the run
- tracks affected by downgrades
---
Adapter doc outline
Use this structure:
# <Runtime name> adapter
## Intent
## Capability summary
## Phase 0: Runtime announcement
## Phase 1: Onboarding mapping
## Verifier policy
## Phase 2: Pre-run preparation
## Phase 3: Execution loop
## Human gates and pause/resume
## Final report behavior
## When not to use this adapter---
Quality bar
An adapter is only acceptable if:
- it never skips approvals
- it never hides downgraded verification
- it never claims unsupported artifacts are available
- it tells the user when the host is the limiting factor
If you cannot meet that bar, classify the runtime as unsupported.
AITune inference optimisation delegation
When the artifact being optimised involves model inference performance — latency, throughput, memory footprint during serving, or GPU utilisation — a* should delegate the low-level inference tuning to AITune rather than blindly mutating inference configurations through the experimental loop.
AITune is NVIDIA's inference optimisation toolkit. It systematically applies compilation, quantization, and graph optimisation across multiple backends, with built-in correctness validation. It does the heavy lifting of finding optimal inference configurations; a* wraps it to ensure the result meets the user's broader quality criteria (accuracy preservation, latency targets, integration constraints).
---
When to delegate to AITune
Delegate when the mission involves any of:
- Reducing model inference latency or improving throughput
- Optimising GPU memory usage during serving
- Applying quantization for deployment (int8, fp16, mixed precision)
- Compiling models for production serving (TensorRT, Torch-TensorRT, etc.)
- Tuning batch size / sequence length configurations for inference
- Deploying models to NVIDIA GPUs with hardware-specific optimisations
Do not delegate when the mission is about:
- Training optimisation (learning rate, batch size during training, loss tuning)
- Prompt optimisation or prompt engineering
- Data pipeline optimisation
- Non-NVIDIA deployment targets
- Artifacts that are not neural network models
The distinction matters because a's experimental loop is designed for problems where the search space is broad and the evaluation is multi-dimensional. AITune already has a principled search over inference backends — wrapping it in a's explore-evaluate-reflect cycle adds structure around the quality constraints (accuracy, latency targets, memory budgets) without reinventing AITune's internal search.
---
How the delegation works
Architecture
a* (autostar) AITune
┌──────────────────────┐ ┌──────────────────────┐
│ Mission definition │ │ │
│ Track rubrics │── calls ──> │ Backend selection │
│ Constraint checking │ │ Quantization │
│ Ratchet / scoring │<── result ── │ Graph optimisation │
│ Round reflection │ │ Correctness checking │
│ Disposition learning │ │ Artifact caching │
└──────────────────────┘ └──────────────────────┘a owns the what (tracks, constraints, scoring, learning); AITune owns the how (which backend, which precision, which graph transforms). Each a step invokes AITune with a parameter set and evaluates the result against all tracks.
Step execution with AITune
Within the standard a* step loop, the mutation phase becomes an AITune invocation instead of a direct artifact edit:
1. Select parameters for this step (backend, precision, batch config, etc.)
2. Invoke AITune with those parameters (see invocation patterns below)
3. AITune produces an optimised model artifact + its own validation report
4. a* runs all track verifiers against the optimised artifact
5. Composite scoring, ratchet, and memory update proceed as normalThe key difference from a normal a* step: the "mutation" is not a text edit but an AITune compilation/tuning run. The artifact is the model; the parameters are AITune configuration knobs.
---
Installation and prerequisites
pip install --extra-index-url https://pypi.nvidia.com aituneSystem requirements:
- Python 3.10+
- PyTorch 2.7+
- TensorRT 10.5.0+ (for TensorRT backend)
- Linux (Ubuntu 22.04+ recommended)
- NVIDIA GPU with appropriate CUDA support
During Phase 2 (pre-run preparation), check AITune availability:
python -c "import aitune; print(aitune.__version__)"If missing, tell the user and offer the install command. Do not begin the run without confirming the environment can support the intended backends.
---
Supported backends
AITune supports multiple compilation backends. Each has different strengths:
| Backend | Best for | Trade-offs |
|---|---|---|
| TensorRT | Maximum throughput on NVIDIA GPUs | Longer compilation; static shapes preferred |
| Torch-TensorRT | PyTorch-native TensorRT integration | Good balance of speed and compatibility |
| TorchAO | Architecture-aware quantization | Flexible precision; PyTorch-native |
| Torch Inductor | Dynamic shapes, general compilation | Broad compatibility; less aggressive optimisation |
When constructing plays, each backend can be a parameter dimension. AITune's own tuning logic handles the intra-backend search; a* handles the inter-backend comparison and quality constraint checking.
---
Tuning modes
Ahead-of-time (AOT) tuning
The user marks specific modules for optimisation. Requires source access but gives maximum control. The API examples below are illustrative — consult the AITune documentation for current syntax.
import aitune
# Illustrative — check AITune docs for current decorator API
@aitune.tune(backend="tensorrt")
class MyModel(nn.Module):
...*When to use in a\:* When the user has a specific model they want to optimise and is willing to modify source code. The a\ mission can iterate over which modules to mark, which backends to apply per module, and what precision to use.
Just-in-time (JIT) tuning
AITune automatically detects optimisable modules without source modification.
import aitune
# Illustrative — check AITune docs for current autotune API
model = load_my_model()
tuned_model = aitune.autotune(model, sample_input=sample)*When to use in a\:* When optimising an existing model without source changes, or when the user wants AITune to find the best configuration automatically. The a\ mission wraps this to validate that the auto-tuned result meets quality constraints across all tracks.
---
Typical track configurations for inference missions
These are starting points — adapt to the specific mission during onboarding. The benchmark and validation scripts below are user-provided (a* does not bundle them). The examples show the expected interface; the user writes or adapts these for their model and evaluation setup. During onboarding, help the user create or locate these scripts.
The {artifact} placeholder refers to the optimised model path. For accuracy tracks, the user must also provide the path to the original (pre-optimisation) model as a mission parameter — store it in mission.md as BASELINE_MODEL and substitute {baseline_model} from there.
Latency track (usually required)
TRACK: inference_latency
required: true
verifier:
type: external_tool
command: "python scripts/bench_inference.py {artifact} --metric=p95_latency --runs=50"
parse_output: regex_capture
pattern: "p95_ms: ([\\d.]+)"
formula: "max(0.0, 1.0 - (p95_ms / target_ms))"
returns: float
required_env: [python, aitune]Throughput track
TRACK: throughput
required: false
weight: 0.30
verifier:
type: external_tool
command: "python scripts/bench_inference.py {artifact} --metric=throughput"
parse_output: regex_capture
pattern: "tokens_per_sec: ([\\d.]+)"
formula: "min(1.0, tokens_per_sec / target_tps)"
returns: float
required_env: [python, aitune]Accuracy preservation track (usually required)
TRACK: accuracy_preservation
required: true
verifier:
type: external_tool
command: "python scripts/validate_accuracy.py {artifact} --reference={baseline_model} --tolerance=0.01"
parse_output: json_path
path: ".accuracy_delta"
returns: float
normalise: "1.0 if abs(delta) < tolerance else max(0.0, 1.0 - abs(delta))"
required_env: [python, aitune]Memory footprint track
TRACK: gpu_memory
required: false
weight: 0.20
verifier:
type: external_tool
command: "python scripts/bench_inference.py {artifact} --metric=peak_memory_mb"
parse_output: regex_capture
pattern: "peak_mb: ([\\d.]+)"
formula: "max(0.0, 1.0 - (peak_mb / budget_mb))"
returns: float
required_env: [python, aitune]---
Play design for inference missions
When plays are enabled, natural parameter bundles for inference optimisation:
PLAY: precision_sweep
parameters:
- (precision, fp32, fp16, int8)
- (backend, tensorrt, torch_inductor)
hypothesis: lower precision with TensorRT should give best latency
tracks_targeted: [inference_latency, throughput, accuracy_preservation]
atomic_fallback: true
PLAY: batch_tuning
parameters:
- (batch_size, 1, 4, 8, 16, 32)
- (sequence_length, 128, 512, 1024)
hypothesis: larger batches improve throughput but may hurt latency
tracks_targeted: [throughput, inference_latency, gpu_memory]
atomic_fallback: true---
Correctness validation
AITune includes built-in correctness checking — it validates that the optimised model produces outputs within tolerance of the original. This is complementary to a*'s track system:
- AITune's check: Fast, automatic, catches gross failures during compilation.
Think of it as a hard constraint gate — if AITune's own validation fails, the step is rejected before a*'s verifiers even run.
- *a's accuracy track:** More thorough, runs on the user's actual evaluation
data, enforces the user's tolerance threshold. This is the authoritative check.
During onboarding, set AITune's internal validation as a hard constraint:
HARD: AITune correctness validation must pass (aitune.validate() returns True)Then use a*'s accuracy track for the scored, ratcheted evaluation.
---
Handling AITune failures
AITune compilation can fail for reasons outside a\*'s control:
- Unsupported operations: Some model ops are not supported by all backends.
TensorRT is the most restrictive; Torch Inductor the most permissive.
- OOM during compilation: TensorRT compilation can require significantly
more GPU memory than inference. This is distinct from inference-time OOM.
- Shape mismatches: Static-shape backends may reject dynamic-shape models.
When AITune fails during a step:
1. Record the failure as outcome: rejected_constraint with the error details. Do not score the step — it produced no artifact. 2. The failure carries useful signal: if a backend consistently fails, exclude it from future plays in the round reflection. This is a legitimate pivot. 3. If all backends fail for the model, escalate to the user — the model may need architectural changes before inference optimisation is viable. 4. Do not retry the same configuration. Move to the next parameter set.
---
Disposition patterns for inference optimisation
Common dispositions that emerge from inference optimisation runs:
- TensorRT dominates for static-shape transformer inference — but only when
compilation time is acceptable. For rapid iteration, Torch Inductor compiles faster with good-enough speedup.
- int8 quantization via TorchAO preserves accuracy better than expected on
most classification and generation tasks. Start with int8 + accuracy track rather than assuming fp16 is needed.
- Batch size and sequence length interact non-linearly with memory — small
batch + long sequence can OOM where large batch + short sequence fits. The a* loop naturally discovers this through the ratchet mechanism.
- JIT tuning finds 80% of the gains with 20% of the effort — for initial
exploration, start with aitune.autotune() before investing in AOT annotation.
These should be seeded into the disposition library when the problem class is inference_optimisation. They will be refined by actual run evidence.
Budgeting reference
---
Budget dimensions
Budget can be set along any combination of these axes:
| Dimension | Unit | Hard ceiling |
|---|---|---|
| Steps | count | Yes |
| Tokens | approximate count | Yes |
| Cost | USD | Yes |
| Wall time | minutes | Yes |
| Rounds | count | Yes |
A run stops when any hard ceiling is reached. Recommend setting at least two dimensions: one primary (steps or cost) and one safety (wall time). This prevents runaway costs from slow tools or unexpected token inflation.
Meta budget: Reserve 10–15% of total token/cost budget for infrastructure: round reflections, user queries, memory consolidation, and the final report. This reservation is protected and cannot be consumed by experiment steps. Set at run start; do not adjust during run.
---
Allocation strategies
1. Front-loaded exploration
Spend more budget in early rounds on wide exploration (more laps, larger parameter ranges). Converge aggressively in later rounds.
Budget split example (100 steps):
Round 1: 40 steps — 5 laps × 8 steps, wide parameter ranges
Round 2: 35 steps — 4 laps × 8-9 steps, narrowed to promising families
Round 3: 25 steps — 3 laps × 8 steps, exploit best directionsWhen to use: Novel problem class; no strong prior dispositions; first run on this artifact type.
2. Track-priority allocation
Allocate more steps to tracks on the critical path; fewer to tracks already passing comfortably.
At the start of each round, compute:
track_budget_share[t] = (1.0 - track_score[t]) × track_weight[t]
normalise to sum to 1.0Laps that primarily affect a high-deficit track get more steps.
When to use: Multiple tracks with uneven baselines; one track is clearly the bottleneck.
3. Confidence-weighted
Allocate more steps to laps where the score distribution shows high variance (the noisy verdict). Fewer steps to laps with clear verdicts.
Each lap requests a step count based on its current variance estimate:
if std > 0.10: request 2 additional steps
if std > 0.20: request 4 additional steps
cap at lap_max_stepsWhen to use: Stochastic generators or LLM judge variance is high; need reliable evidence before advancing the ratchet.
4. Pace-aware
The budget controller maintains a running projection:
steps_remaining = (budget_remaining) / (avg_step_cost)
improvement_rate = regression over last N steps
projected_score = current_score + (steps_remaining × improvement_rate)
if projected_score < target × 0.85: → pace_risk flag
if projected_score > target × 1.10: → budget_slack flagpace_risk feeds into the round reflection's "ask user" trigger. budget_slack gives the orchestrator permission to explore rather than exploit in the next round.
Use this strategy always, in combination with others. It is a monitoring overlay, not a standalone allocation strategy.
5. Reserve-and-release
Hold back 20% of each round's budget as reserve. Release it if:
- The round's best lap is
promisingand additional steps would likely confirm - A play has shown strong preliminary results across 2+ steps
Forfeit the reserve if:
- All laps returned
exhaustedby the halfway point - The round is clearly plateau'd
When to use: When you want to be aggressive on strong signals while not wasting budget on weak directions.
---
Budget negotiation dialogue
Present the user with a concrete proposal:
"Based on your tracks (N required, M weighted) and the verifier types,
a single step will cost approximately X tokens. Here are three options:
>
Quick pass (30 steps): ~Y tokens / ~$Z. Gives you a rough sense of
the improvement space. 2–3 rounds, limited exploration.
>
Standard run (80 steps): ~Y tokens / ~$Z. Proper exploration +
exploitation. 3–4 rounds with reflections. Recommended for most tasks.
>
Thorough run (150+ steps): ~Y tokens / ~$Z. Deep map of the parameter
space. 5+ rounds. Best for critical artifacts or novel problem classes.
>
You can also set a hard cost ceiling and let me work within it."
Adjust estimates based on actual verifier costs (external tool calls are cheap; LLM judge ensemble calls are expensive).
---
Budget controller: decision table
The budget controller evaluates at the end of every lap:
| Condition | Action |
|---|---|
| Budget > 80% remaining | No action |
| Budget 50–80% remaining, pace on target | No action |
| Budget 50–80% remaining, pace_risk flag | Note in round reflection |
| Budget 30–50% remaining, pace_risk flag | Trigger "ask user" in next round reflection |
| Budget < 30% remaining | Switch to exploit-only strategy (no exploration) |
| Budget < 15% remaining | Final round; write post-run report after completion |
| Meta budget < 5% remaining | Stop experiments immediately; run final report |
| Any hard ceiling reached | Graceful shutdown; run final report |
---
Cost estimation by verifier type
Rough guidance for budget estimation:
| Verifier type | Cost per step |
|---|---|
| Deterministic | Negligible |
| External tool (fast: pyright, tsc) | Negligible |
| External tool (slow: lighthouse, pytest with coverage) | 5–30 seconds wall time |
| LLM judge (ensemble: 1) | ~800–1500 tokens |
| LLM judge (ensemble: 2) | ~1600–3000 tokens |
| Mutation agent call | ~1000–2000 tokens |
| Orchestrator reasoning step | ~500–1000 tokens |
| Round reflection | ~1500–2500 tokens |
For a step with 2 required external tools + 3 LLM judge tracks (ensemble 1): approximate cost ≈ 3500–5500 tokens + tool wall time.
Memory reference
---
Architecture overview
One canonical persistent backend. One run-scoped append-only store. Human-readable JSON and JSONL files are exported mirrors or project-pack views, not the primary database.
CANONICAL LONG-TERM BACKEND (persistent, source of truth)
SQLite-backed store
episodes — append-only episodic memory
run_summaries — one summary per completed run
dispositions — current disposition records
disposition_versions — auditable version history
disposition_updates — pending/applied proposals
project_state — compact project-scoped state
EXPORTED MIRRORS / PROJECT PACKS (derived from backend)
dispositions.json
episodes.jsonl
run-summaries.jsonl
project-state.json
latest-relevant-priors.json
SHORT-TERM (run-scoped, append-only where stated)
step_log.jsonl — append-only; every step record
reflections.jsonl — append-only; every round reflection
hypothesis_stack.json — current queue with provenance
track_trajectories.json — per-track score history
momentum.json — slope and acceleration of composite scoreIf a derived snapshot and an append-only run log disagree, the append-only log wins.
---
Short-term memory
step_log.jsonl
Append-only. One JSON object per line. Schema matches the step record in the main SKILL.md. Never truncated during a run.
Key fields for orchestrator consumption:
outcome— keep/revert/partial_keep/rejected_constraintjudge_notes— per-track rationale stringsplay— which play was attempted (or null)composite— the score that determines the ratchet
hypothesis_stack.json
An ordered list of mutation hypotheses the orchestrator intends to try, with provenance for each:
[
{
"hypothesis": "Adding explicit return type annotations may improve pyright score",
"source": "disposition:type_correctness:python_typing",
"confidence": 0.74,
"play": "annotation_bundle",
"priority": 1
},
{
"hypothesis": "Extracting nested conditionals into helper functions may improve readability",
"source": "orchestrator_reasoning:round_2_reflection",
"confidence": 0.55,
"play": null,
"priority": 2
}
]The orchestrator pops from the top and may re-insert refined hypotheses based on step outcomes.
momentum.json
{
"window": 5,
"composite_slope": 0.012,
"composite_acceleration": -0.003,
"per_track": {
"type_correctness": {"slope": 0.0, "plateau": true},
"docstring_quality": {"slope": 0.024, "plateau": false}
},
"signal": "exploiting_successfully | plateau | diverging | recovering"
}The signal field feeds the round reflection's worth-pursuing assessment.
---
Long-term episodic store
episodes.jsonl is the exported mirror of the canonical episodic store. The SQLite backend is the source of truth; the mirror exists for inspection, packaging, and Claude.ai project-pack workflows.
Each entry is a round reflection record (verbatim from the round reflection output, plus run metadata). This store is the raw historical record. It is queried at run start to retrieve relevant prior round reflections for similar problem classes.
run_summaries.jsonl is the exported mirror of the canonical run-summary table. One entry per completed run:
{
"run_id": "run_20260324",
"problem_class": "python_api_optimisation",
"artifact_description": "FastAPI handler for user authentication",
"baseline_scores": {...},
"final_scores": {...},
"rounds_completed": 4,
"pivots": ["minor pivot at round 2: switched to contrastive_negation strategy"],
"what_worked": ["annotation_bundle play: +0.22 type_correctness"],
"what_failed": ["docstring_length increase: no significant effect"],
"disposition_updates_proposed": [...]
}---
Disposition library
Schema
{
"problem_class": "python_api_optimisation",
"action_intent": "improve_type_correctness",
"version": 3,
"prior": "When improving type correctness in Python API handlers, prioritise
return type annotations before parameter annotations — pyright errors
on return types more frequently than on parameters. Use TypeAlias for
complex union types rather than inline. Avoid annotating *args and
**kwargs unless the function is part of a public interface.",
"confidence": 0.81,
"n_supporting": 14,
"n_refuting": 2,
"exemplars_supporting": ["run_20260310_r2_l1", "run_20260318_r1_l3"],
"exemplars_refuting": ["run_20260301_r3_l2"],
"provenance": "learned_from_run",
"source": null,
"override_conditions": "Suspend when the codebase uses Pydantic v1 (type
inference rules differ significantly from standard mypy/pyright).",
"last_updated": "2026-03-22",
"policy_version_at_creation": 2
}Keying and retrieval
Dispositions are keyed on (problem_class, action_intent) but retrieved by semantic similarity with exact-key boosts, not exact match alone. At run start:
1. Build a deterministic hashed word-and-character n-gram vector from the run's problem description, goal, artifact description, and each anticipated action intent 2. Query the disposition library with cosine similarity over those vectors 3. Boost exact matches on problem_class and action_intent 3. Return top-3 dispositions per action class with confidence ≥ 0.4 4. Inject retrieved dispositions into the orchestrator's context as:
"Based on prior experience with similar problems, when attempting
[action_intent], note: [prior text] (confidence: X, n=Y)"
If confidence < 0.4, flag as weak prior and consider triggering meta-research.
Updating dispositions
The memory agent proposes updates after each round. Updates are not applied automatically — they are queued as proposals in the canonical backend and applied only when the run completes and the user approves (or auto-approved if confidence delta is small and policy allows it).
Update types:
Reinforce: A disposition was retrieved and the action it conditioned produced a better-than-average outcome. Increase confidence, add exemplar.
Weaken: A disposition was retrieved and the action produced worse-than- expected outcome. Decrease confidence, add refuting exemplar.
Extend: New override condition discovered (orchestrator flagged a case where the disposition didn't apply). Add to override_conditions.
Fork: Evidence suggests the problem class should be split into two sub-classes with different dispositions. Propose fork; user approves.
Create: No relevant disposition existed; a new one is proposed from run experience.
Retire: Confidence has fallen below 0.2 with n > 10. Mark as retired; do not retrieve for new runs.
Meta-research step
Triggered when: no relevant disposition exists, OR confidence < 0.4 for a critical action class.
Protocol: 1. Identify the action class and problem class in plain language 2. Check the mission's research_policy 3. If research_policy.enabled is false, abort the meta-research step 4. Formulate a best-practice query that avoids sending source artifacts or secrets 5. Prefer local references, bundled docs, and installed tool help first 6. If external lookup is allowed, prefer allowlisted/vendor documentation before general web search 7. Only include artifact/code excerpts in an external query if artifact_sharing was explicitly approved 8. Synthesise the retrieved content into a candidate disposition prior 9. Record provenance as looked_up_from_web with source URL 10. Apply the candidate on the next relevant action 11. Observe outcome; update confidence accordingly
The meta-research step costs budget. Gate it:
- Do not trigger if budget_remaining < 20%
- Do not trigger more than once per round per action class
- Record the query and source in
step_log.jsonlas a special
meta_research entry
- Record whether the step used
local_only,allowlisted_external, oropen_web
Default policy:
- External research is disabled unless the user explicitly enabled it during onboarding
- Artifact sharing to external services is disabled unless separately approved
---
Claude.ai access paths
Claude.ai should never treat native Claude memory as the authoritative store for a* learning. Use one of these explicit paths instead:
1. connector_backed Preferred. A remote connector exposes narrow memory tools over a user-scoped, auditable surface. 2. project_pack Fallback. Export a text-first project pack from the canonical backend, add it to project knowledge, and manually sync updated pack files back after the run. 3. none Final fallback. Run with short-term memory only and say so plainly.
Memory agent responsibilities
The memory agent runs:
1. After every step: append step record to step_log.jsonl; update track_trajectories.json and momentum.json
2. After every lap: update hypothesis stack (remove tested, add refinements based on outcomes)
3. After every round reflection: append to episodes.jsonl; identify disposition update proposals; check for meta-research triggers
4. After run completion: write run_summaries.jsonl entry; apply approved disposition updates to library; write final report
Onboarding reference
Onboarding is a structured interview, not a form fill. Work through the four phases below in order. At every checkpoint marked [ASK], you must stop and use the ask_user tool before proceeding. Do not infer and continue.
If the user's initial message already answers a question, present that answer as a pre-selected option and ask them to confirm or change it. Never silently accept an inferred value.
---
Phase A: Goal decomposition
A1. Open goal description
If the user has not already described their goal in detail, ask in prose (not ask_user — this is genuinely open-ended):
"Before we configure anything, describe what a perfect output looks like.
Don't worry about measurability — just tell me what 'good' means here.
What would make you look at the result and say 'yes, that's it'?"
Read their answer carefully. Identify the distinct qualities they mentioned. A good goal description usually contains 2–6 separable dimensions. Name them.
A2. Track candidates [ASK]
Present your inferred tracks as a multi-select. Introduce the widget with prose:
"From your description I can see a few distinct qualities we could track
and optimise independently. Select the ones that matter — and tell me
below the widget if I've missed any."
ask_user(
question: "Which of these dimensions should we track and optimise?",
type: multi_select,
options: [<inferred track 1>, <inferred track 2>, ..., "Something else"]
)If they select "Something else", follow up in prose. Add it to the list and loop back to confirm the full set before moving on.
Example (Python API handler): User said: "I want it cleaner, faster, and safer." Inferred tracks to present: Code readability, Docstring quality, Response latency, Type correctness, No security vulnerabilities.
A3. Required vs preferred [ASK]
For each confirmed track, ask explicitly. Do not assume. Run one widget per track — batch them so the user sees all in one go:
"Some tracks are absolute requirements — the output fails if they don't
pass, regardless of everything else. Others are preferences where a lower
score is acceptable. For each track, which is it?"
ask_user(
question: "Is '[track name]' a hard requirement or a preference?",
type: single_select,
options: ["Hard requirement — failure if not met", "Preference — weighted in the score"]
)Repeat for each track. If the user marks everything as required, probe gently:
"If all tracks are required, the optimiser has very little room to work.
Are any of these more 'it would be nice' than truly mandatory?"
A4. Relative importance of preferences [ASK]
For tracks marked as preferences only:
ask_user(
question: "Rank these tracks by importance (top = most important):",
type: rank_priorities,
options: [<preference tracks>]
)Convert the ranking to weights and reflect them back in prose:
"So type correctness (0.35) counts for more than documentation quality
(0.20) in the composite score. Does that feel right?"
Ask for verbal confirmation before committing the weights.
---
Phase B: Verifier elicitation
For each track, determine how it will be evaluated. Work through required tracks first, then preferences in priority order.
Runtime gate
As soon as the verifier types are known for the mission, run a runtime compatibility check before spending time on detailed rubric/budget work.
Use:
python scripts/runtime_profile.py check-mission <runtime-profile> \
--verifier <type> \
--verifier <type> \
--require-file-read-write fullAdd flags when needed:
--require-subprocessif any track needsexternal_toolor subprocess-backedhybrid--require-local-htmlonly if the user explicitly requires the rendered visualiser UI--require-long-term-memoryif cross-run memory is required rather than optional
If the command fails: 1. stop onboarding 2. tell the user exactly which mission requirement the runtime cannot satisfy 3. ask whether to switch runtimes, remove the track, or accept a downgrade
Do this before deep rubric elicitation so unsupported verifier mixes are rejected early.
B1. Verifier type per track [ASK]
ask_user(
question: "How should '[track name]' be evaluated?",
type: single_select,
options: [
"Run a command-line tool automatically (pyright, pytest, axe, lighthouse, vale...)",
"Check a precise rule or formula (word count, regex, schema validation...)",
"AI judge with a scoring rubric I define",
"Combination: a tool check AND an AI judge",
"Pause and ask me each time (human gate)"
]
)If "command-line tool": Ask which tool in prose, or offer common options for the domain. Then confirm availability:
"I'll need [tool] installed and on PATH. Can you confirm it's available,
or shall I suggest how to install it? If it's not available, I can use an
AI judge as a fallback — lower confidence, but it'll work."
If "AI judge" or "combination": Proceed to rubric elicitation (B2) before moving to the next track.
If "human gate": Ask why it can't be automated — sometimes this reveals a rubric that can be. If they confirm it genuinely needs human judgement, accept it and note that it will pause the run and consume budget.
B2. Rubric elicitation for LLM judge tracks
Claude drafts the rubric, but only from user-supplied anchors. Do not invent the intent of the rubric yourself.
Anchor the extremes (prose):
"For the '[track name]' judge:
What does a perfect score — 1.0 — look like? Be specific.
What does complete failure — 0.0 — look like?"
Anchor the midpoint (prose):
"What does a middling result — roughly 0.5, neither good nor bad —
look like for this track?"
Name the failure modes (prose):
"What specific things should push the score down? What should the judge
actively penalise?"
Draft the rubric from their answers and show it back. Then use a bounded approval:
ask_user(
question: "For '[track name]', what should I do with this drafted rubric?",
type: single_select,
options: [
"Keep this draft and move on",
"Tighten the wording but keep the same intent",
"Redo this track from my description"
]
)If they choose "Tighten the wording", revise the draft and ask again. If they choose "Redo this track", re-elicit the anchors.
Mark each accepted draft as provisional until all rubric-bearing tracks have been drafted.
B3. Final rubric review [ASK]
After all llm_judge and hybrid tracks have provisional drafts, show the full rubric-bearing section of tracks.md back to the user. Make it explicit that approval here locks the rubrics for the run.
ask_user(
question: "Are these inferred rubrics correct and ready to lock for this run?",
type: single_select,
options: [
"Yes — lock these rubrics",
"Edit one specific track",
"No — rework the rubric set"
]
)If they choose "Edit one specific track", ask which track and loop back to B2 for that track only. If they choose "No", ask which rubrics are off and revise only the relevant drafts.
The rubrics are not committed until the user selects "Yes — lock these rubrics". Once committed, they do not change during the run.
B4. Runtime compatibility confirmation
Once all verifier types are selected, run the runtime gate immediately. If you already ran it earlier in Phase B, summarise the result again here before moving on:
"I've checked this mission against the active runtime profile. [It is compatible / It is not compatible because ...]."
If incompatible, do not proceed to constraints/budget until the user has resolved the mismatch.
---
Phase C: Constraint elicitation
C1. Hard constraints [ASK]
Open with prose:
"Are there things the output absolutely cannot do — things that would
make the result unacceptable regardless of score? For example: must not
exceed a certain length, must not change a function signature, must not
introduce new dependencies."
After their answer, reflect the list back and ask for confirmation:
ask_user(
question: "I've noted these as hard constraints. Anything to add or remove?",
type: multi_select,
options: [<inferred constraints from their answer> + "Add another" + "Remove one"]
)C2. Soft constraints
Ask in prose — soft constraints are usually idiosyncratic and don't benefit from a widget:
"Any stylistic or conventional preferences that should guide mutations,
even if they're not deal-breakers? For example: prefer a certain naming
convention, avoid a certain pattern, use a specific style guide."
C3. External research policy [ASK]
Ask explicitly whether the run may use any external research beyond local files, bundled references, installed tool help, and prior run memory.
ask_user(
question: "May this run use external research if local guidance is insufficient?",
type: single_select,
options: [
"No — local evidence only",
"Yes — vendor docs / allowlisted sources only",
"Yes — open web allowed with approval gates"
]
)Rules:
- Default to
No — local evidence onlyunless the user explicitly opts in - If the user picks an external option, ask whether artifact text/code may be quoted externally; default to no
- If they want allowlisted sources only, ask them to name the allowed domains or source classes
- Reflect the resulting policy into
mission.json/mission.mdbefore execution - If the user does not opt in, do not perform web search, documentation fetch, or remote best-practice lookup during the run
Summarise back and ask for verbal confirmation. No widget needed here.
---
Phase D: Budget and plays
D1. Budget ceiling [ASK]
Estimate cost per step based on the verifier types configured. Then present three concrete options with real numbers, not vague descriptions. Fill in the actual estimates before showing:
ask_user(
question: "How thorough should this run be? (Each step costs ~[X] tokens / ~[Y]s)",
type: single_select,
options: [
"Quick — ~30 steps, ~[N] tokens. Sense-check the space in [time].",
"Standard — ~80 steps, ~[N] tokens. Proper exploration in [time]. Recommended.",
"Thorough — ~150 steps, ~[N] tokens. Deep map of the space in [time].",
"I'll set my own ceiling"
]
)If they choose "I'll set my own ceiling", ask:
ask_user(
question: "Which dimension do you want to cap?",
type: single_select,
options: ["Maximum steps", "Maximum tokens", "Maximum cost (USD)", "Maximum wall time"]
)Then ask for the value in prose.
D2. Budget allocation strategy [ASK]
ask_user(
question: "How should budget be spread across experiments?",
type: single_select,
options: [
"Front-loaded — explore widely early, converge later (good for novel problems)",
"Track-priority — spend more on whichever track is furthest from target",
"Confidence-weighted — spend more where results are noisy and uncertain",
"Let me decide round by round — flag me when strategy should change"
]
)D3. Plays [ASK]
ask_user(
question: "How should I handle parameter changes?",
type: single_select,
options: [
"Group related parameters into coordinated plays (I'll propose bundles for approval)",
"Change one parameter at a time — strictly atomic (cleaner attribution)",
"Mix — use plays when parameters seem linked, atomic otherwise"
]
)If plays are enabled, propose initial bundles in prose: name each one, state which parameters it bundles, and the hypothesis behind it. Then:
ask_user(
question: "Which of these proposed plays should I use?",
type: multi_select,
options: [<play name: one-line hypothesis> + "None — I'll describe my own" + "Skip plays for now"]
)---
Phase E: Final confirmation [ASK]
Before any step runs, show the complete mission summary in prose. Be explicit:
"Here's the full configuration. Please read through before I begin anything."
Show:
- Tracks table: name | verifier type | required or weighted | weight
- Hard constraints: bulleted list
- Soft constraints: bulleted list
- Budget: ceiling, strategy
- Plays: enabled/disabled, list of approved plays
Then ask a single binary question:
ask_user(
question: "Ready to begin the run?",
type: single_select,
options: [
"Yes — run the baseline step and start",
"No — I want to change something first"
]
)If "No", ask in prose what they want to change and navigate directly to the relevant phase. Do not restart the whole onboarding from the top.
Only proceed to Phase 2 of the main skill on explicit "Yes".
Runtime capability contract
This file defines the portability layer for a. The skill is authored against abstract runtime capabilities*, not against Claude-specific tool names. Claude Code / Claude.ai are reference adapters, not the specification.
If you are implementing a* in another agent framework, start here.
Concrete examples and scaffolds:
runtime-profiles/claude-code.jsonruntime-profiles/codex.jsonruntime-profiles/gemini.jsonruntime-profiles/claude-ai.jsonruntime-profiles/pi.jsonruntime-profiles/chat-only.jsonruntime-profiles/template.jsonreferences/adapter-claude-code.mdreferences/adapter-codex.mdreferences/adapter-gemini.mdreferences/adapter-claude-ai.mdreferences/adapter-pi.mdreferences/adapter-chat-only.mdreferences/adapter-template.mdscripts/runtime_profile.py
---
Goals
The adapter layer exists to preserve four invariants across runtimes:
1. User approval checkpoints cannot be skipped. 2. Verifier configuration cannot silently drift during a run. 3. Human gates must actually pause optimisation. 4. Unsupported features must degrade explicitly, not fail half-hidden.
---
Capability model
Each runtime should expose a capability profile with the following keys:
runtime:
name: <string>
version: <string|null>
capabilities:
structured_choice: full | basic | none
freeform_input: true | false
file_presentation: inline | external | none
local_html: inline | external | none
subprocess: true | false
pause_resume: true | false
file_read_write: full | limited | none
long_term_memory: true | falseAt run start, detect this profile and adapt the workflow before onboarding. Keep the checked-in base profile conservative. If the current session can probe an actual memory surface, emit an effective profile alongside the base profile instead of pretending the base profile changed.
---
Capability definitions
1. structured_choice
Used for bounded decisions: track confirmation, verifier selection, budget, plays, and final go/no-go approval.
Contract:
- Present 2+ explicit options.
- Allow the user to choose one or more where appropriate.
- Return the selected value(s) in a machine-readable form.
- Never auto-select without an explicit user confirmation event.
Native examples:
- Claude Code:
ask_user - Chat UIs without forms: numbered options in markdown + explicit user reply
Fallback:
- If only
basic, present numbered choices in plain text. - If
none, a* is not portable without adding an approval wrapper.
2. freeform_input
Used for open-ended goal descriptions, constraints, rubric wording, and reflection prompts that do not fit bounded choices.
Contract:
- Preserve the user's raw text.
- Do not coerce freeform input into a prefilled structure unless the user
confirms the transformation.
Fallback:
- If absent, the runtime is not suitable for onboarding.
3. file_presentation
Used to surface tracks.md, generated reports, visualiser.html, and any artifact the user must review.
Contract:
- Present a file or file-derived content to the user.
- Make the exact reviewed artifact identifiable by path or stable name.
Modes:
inline: the host can render or attach the file directlyexternal: the host can only point the user to a file path or downloadnone: no reliable way to present artifacts
Fallback:
- If
external, tell the user exactly which file to open and why. - If
none, replace file presentation with pasted summaries only for
non-binding status updates; do not use this mode for human gates.
Preference rule:
- If
inline, prefer presenting review artifacts and rendered visualisers inline
rather than redirecting the user to an external browser or file path.
4. local_html
Used for the live visualiser when the runtime can render local HTML.
Contract:
- Surface a local HTML artifact either inline or by opening it externally.
- Preserve the generated output file so the user and agent refer to the same
artifact.
Modes:
inline: embedded browser/file renderingexternal: open in system browser or provide a path to open manuallynone: runtime cannot surface local HTML
Fallback:
- Visualiser: fall back to text summaries plus
progress.json.
5. subprocess
Used for external-tool verifiers, tool availability checks, and rendering the visualiser HTML.
Contract:
- Run a command with cwd, timeout, and captured stdout/stderr.
- Return exit code and output.
- Allow preflight checks such as
tool --version.
Fallback:
- If absent, external-tool tracks must be rejected or replaced during
onboarding. Mark the replacement as lower-confidence in the run report.
- The visualiser must be replaced by text progress plus
progress.json. - Never silently convert an
external_toolverifier into anllm_judge.
6. pause_resume
Used for human gates and round-level escalations where optimisation must stop until the user responds.
Contract:
- Suspend autonomous mutation after a checkpoint is emitted.
- Resume only after a user message is received and bound to that checkpoint.
Fallback:
- If absent, the runtime must run synchronously and block on the next user
turn. If even that is impossible, human-gate tracks are unsupported.
7. file_read_write
Used for run artifacts: mission.md, tracks.md, constraints.md, plays.md, step_log.jsonl, reflections.jsonl, progress.json.
Contract:
- Read and write stable files in a run directory.
- Preserve append-only logs unless the schema explicitly says overwrite.
Fallback:
- If
limited, a* can run in reduced mode but may lose append-only logs or
stable run directories.
- If
none, a* can only run in ephemeral mode and loses auditability. This is
acceptable for demos, not for the full skill.
8. long_term_memory
Used for episodic memory and dispositions across runs.
Contract:
- Store and retrieve prior reflections and disposition records keyed by problem
class and action intent.
- Only advertise long-term memory when a real surface exists for this session.
Memory access modes:
direct_backend— runtime can reach the canonical local backend directlyconnector_backed— runtime uses a connector tool surfaceproject_pack— runtime reads and writes a text-first project pack with manual syncnone— no long-term memory surface is available
Fallback:
- If absent, run with short-term memory only and report that cross-run learning
is disabled.
- Do not treat host-native memory synthesis as the system of record for
dispositions, episodes, approvals, or run summaries.
---
Support levels
Use these support levels when adapting a* to a host runtime:
Full support
Required:
structured_choice:fullorbasicfreeform_input: truefile_presentation:inlineorexternalsubprocess: truepause_resume: true or synchronous block equivalentfile_read_write:full
Optional but recommended:
local_htmllong_term_memory
Reduced support
Allowed with explicit downgrade messaging:
- No
local_html - No
long_term_memory structured_choice: basicfile_presentation: externalfile_read_write: limited
Unsupported
Do not claim portability if any of these are true:
freeform_input: falsestructured_choice: nonefile_read_write: nonepause_resume: falseand no synchronous blocking alternative
---
Required runtime shims
An adapter should expose these abstract operations:
choose(prompt, options, allow_multiple=false) -> selection
ask(prompt) -> text
present(path, purpose, mode=inline|external) -> acknowledgement
run(command, cwd=null, timeout_s=30) -> {exit_code, stdout, stderr}
pause(checkpoint_id, prompt, artifacts=[]) -> user_response
read(path) -> bytes|text
write(path, content)
append(path, content)
memory_lookup(query) -> records[]
memory_store(record)The exact API shape is host-specific. The behavior is not.
---
Mapping examples
Claude Code
structured_choice: full
freeform_input: true
file_presentation: external
local_html: external
subprocess: true
pause_resume: true
file_read_write: full
long_term_memory: falseTypical mapping:
choose->ask_userpresent-> file path + browser openrun-> shell tool
Claude.ai / Claude Desktop / Claude Mobile
structured_choice: basic
freeform_input: true
file_presentation: inline
local_html: inline
subprocess: false
pause_resume: true
file_read_write: limited
long_term_memory: falseTypical mapping:
choose-> structured chat promptpresent->present_filesrun-> unsupported
Implication:
- External-tool tracks must be replaced or disabled.
- If
visualiser.htmlalready exists, present it inline rather than linking out.
Chat-only agent with no file or command tools
structured_choice: basic
freeform_input: true
file_presentation: none
local_html: none
subprocess: false
pause_resume: true
file_read_write: false
long_term_memory: falseImplication:
- Not a valid full a* host.
- Can only run a narrowed "prompt optimisation only" mode if the implementation
explicitly removes file-backed auditing and tool-based verifiers.
Concrete profile:
runtime-profiles/chat-only.jsonreferences/adapter-chat-only.md
---
Fallback policy
When a capability is missing, degrade in this order:
1. Replace the host-specific tool with an abstract equivalent. 2. Replace the feature with a lower-fidelity but still explicit workflow. 3. Reconfigure the mission during onboarding. 4. If the invariant would be violated, stop and tell the user the runtime is unsupported for that track or for the whole run.
Never silently:
- turn an external-tool verifier into an LLM judge
- skip a human gate
- skip final mission approval
- pretend a file was presented when only a summary was shown
---
Implementation guidance
When porting a* to another tool:
1. Detect capabilities before Phase 1. 2. Announce the active runtime profile to the user. 3. Apply downgrades before proposing tracks. 4. Record all downgraded features in mission.md and the final report. 5. Prefer portable artifacts:
tracks.mdfor rubric confirmationprogress.jsonfor status- text-based trajectory summaries when HTML is unavailable
---
Current portability boundary
Today, the bundled skill is native-first for Claude environments. This contract exists so those assumptions can be moved behind adapters over time instead of being hard-coded into the workflow forever.
{
"runtime": {
"name": "Chat-only",
"version": null
},
"support_level": "unsupported",
"capabilities": {
"structured_choice": "basic",
"freeform_input": true,
"file_presentation": "none",
"local_html": "none",
"subprocess": false,
"pause_resume": true,
"file_read_write": "none",
"long_term_memory": false
},
"native_mappings": {
"choose": "plain chat prompt with numbered replies",
"ask": "normal conversation turn",
"present": null,
"run": null,
"pause": "wait for next user response",
"read": null,
"write": null,
"append": null,
"memory_lookup": null,
"memory_store": null
},
"downgrades": [
{
"capability": "file_presentation",
"effect": "no canonical file review flow"
},
{
"capability": "local_html",
"effect": "visualiser unavailable"
},
{
"capability": "subprocess",
"effect": "external_tool and subprocess-backed hybrid verifiers unavailable"
},
{
"capability": "file_read_write",
"effect": "no persistent run artifacts or append-only logs"
}
]
}
{
"runtime": {
"name": "Claude.ai",
"version": null
},
"support_level": "reduced",
"capabilities": {
"structured_choice": "basic",
"freeform_input": true,
"file_presentation": "inline",
"local_html": "inline",
"subprocess": false,
"pause_resume": true,
"file_read_write": "limited",
"long_term_memory": false
},
"native_mappings": {
"choose": "structured chat prompt",
"ask": "normal conversation turn",
"present": "present_files",
"run": null,
"pause": "wait for next user response",
"read": "session/local file access when available",
"write": "session artifact or limited file output",
"append": "session artifact or limited file output",
"memory_lookup": null,
"memory_store": null
},
"downgrades": [
{
"capability": "subprocess",
"effect": "external_tool verifiers unavailable"
},
{
"capability": "subprocess",
"effect": "render_visualiser.py unavailable during run"
},
{
"capability": "file_read_write",
"effect": "run artifacts may need to be represented canonically in chat"
}
]
}
{
"runtime": {
"name": "Claude Code",
"version": null
},
"support_level": "full",
"capabilities": {
"structured_choice": "full",
"freeform_input": true,
"file_presentation": "external",
"local_html": "external",
"subprocess": true,
"pause_resume": true,
"file_read_write": "full",
"long_term_memory": false
},
"native_mappings": {
"choose": "ask_user",
"ask": "normal conversation turn",
"present": "file path and/or local browser open",
"run": "shell/subprocess execution",
"pause": "wait for next user response",
"read": "filesystem read",
"write": "filesystem write",
"append": "filesystem append",
"memory_lookup": null,
"memory_store": null
},
"downgrades": []
}