Prior Work Deep-Dive · grounded in source code

symbolica bestiary (agentica) — a multi-agent system whose knowledge boundary is drawn by a prompt

Every quote on this page is taken verbatim from engine/agents/templates/agentica/ (prompts.py, scope/roles.py, skills/, sleep/, wake/). Our engine is a fork of this codebase, so what is written here is both “prior work” and our own lineage.

01

The system in one line

An ARC-AGI-3 harness on the Agentica SDK (Arcgentica): an orchestrator LLM that never plays the game itself spawns and drives explorer · theorist · tester · solver subagents, while shared memories and a posterior-carrying skills library ferry knowledge across agent lifetimes. Wake (playing the game) and sleep (optimizing the skill library) run symmetrically on the same Phase lifecycle, and inside sleep a separated optimization loop runs between the miner (generation) and the judge (evaluation).

The device that keeps knowledge from leaking in from the game implementation is not code but prompt text: the GAME_REFERENCE constant, mandatorily passed to every subagent, pins down “everything the agent is allowed to know” in a single document.

02

GAME_REFERENCE — the knowledge-leak boundary

prompts.py — GAME_REFERENCE (module constant, f-string; defined from ~line 437)

It reveals only the interface contract (the 64×64 integer grid, six actions, RESET semantics, the Frame helper API) and not a single character of game-specific mechanics. Key excerpt (verbatim):

unfold source — GAME_REFERENCE: forcing relational thinking (prompts.py)
This is a visual game designed for humans. You see it as a 64x64
coordinate grid of integers 0-15 ({COLOR_LEGEND}), due to the nature and limitations
of your interface. You use coordinates to identify positions and click, but game
mechanics and win conditions are about relationships between elements, not positions
on the grid. Think "A must reach B" not "A must reach row 38." If your
hypothesis includes a specific coordinate as part of the goal, it is wrong --
restate it in terms of what must relate to what.
Render the grid and read it as a picture.
unfold source — GAME_REFERENCE: Forming good hypotheses (prompts.py)
Forming good hypotheses: When something interesting happens, don't just note the
  event -- note what else was true at that moment. What were other elements doing
  relative to each other? The relationship between elements is often the actual rule.
  Never trust a hypothesis based on a single observation. Reproduce the effect from
  a different starting state to separate the actual rule from coincidences of that
  particular configuration.

Because the boundary is “one document,” leak experiments are also managed as gates inside this one file. For example, only when A3_DECODE_STATE=1 does _DECODE_STATE_BLOCK (a block spelling out one game’s code-tuple lock state) get injected into GAME_REFERENCE; at the default, “the emitted prompt is byte-identical to the current un-gated text” (source docstring, verbatim) is guaranteed. That is: “what leaks” is always collected at one diff-able point.

The delivery contract is also written into the prompt itself — orchestrator premise, verbatim: “Always include GAME_REFERENCE in the system prompt”, “Always pass GAME_REFERENCE=GAME_REFERENCE, history=history, and memories=memories to every subagent.” The premise that a fresh subagent knows nothing (“A new subagent knows NOTHING about the game.”) is the boundary’s other face.

03

THEORIST premise — hypothesis discipline: mechanisms, never coordinates

scope/roles.py — _THEORIST_PREMISE (full text)

unfold source — _THEORIST_PREMISE, full (scope/roles.py)
You are the THEORIST. The orchestrator calls you once before each acting turn
to propose hypotheses for HOW TO CLEAR THIS LEVEL -- your reasoning is folded
into the trace so the skill-miner and the judge can see whether a skill
ADVANCES a hypothesis you named (vs repeating an exhausted one).

Read the trace + memories. Propose 2-3 concrete HYPOTHESES for how to CLEAR
THIS LEVEL -- mechanic-based, NEVER absolute coordinates. Each hypothesis is one
testable sentence: name the MECHANIC and the OBSERVATION that would confirm or
refute it. Mark any hypothesis the memories show was already tried with no goal
change as EXHAUSTED, and prefer a structurally different one.

YOU MUST NOT call spawn_agent, submit_action, eval/exec/subprocess.

Three disciplines are pinned down sentence by sentence. ① Mechanism-based, absolute coordinates forbidden — a hypothesis may only be stated as “what must relate to what” (the same axis as GAME_REFERENCE’s “A must reach B, not row 38”). ② Falsifiability — one hypothesis = one testable sentence, and the observation that would confirm or refute it must be named alongside. ③ EXHAUSTED marking — a hypothesis already tried with no goal change is marked exhausted, and a structurally different one is preferred. The theorist’s reasoning is folded into the trace and becomes the miner’s and judge’s scoring criterion (hypothesis progress).

Spawn condition (source comment, verbatim): “Spawned (and CALLED) once per acting turn ONLY when A3_THEORIST_PROGRESS is on (agent.py wake); OFF => never spawned. It is NOT a sleep-internal role.” The orchestrator premise’s Hypothesize step carries the same discipline: “Reject any hypothesis stated in absolute coordinates -- mechanics are always relational.”

SKILL-AGENT (miner) premise — the evidence protocol

scope/roles.py — _SKILL_AGENT_PREMISE, excerpt

unfold source — _SKILL_AGENT_PREMISE: EVIDENCE PROTOCOL (scope/roles.py)
EVIDENCE PROTOCOL (mandatory):
  ...
  2. Ground each candidate in `evidence`: >=10-word verbatim quotes from
     memory.details or trace_digest lines.
  3. Write task-agnostic, coordinate-free skills: never reference a task
     name, a level number, or a grid coordinate -- the judge scores these as
     grounding failures.

The miner’s output is a list[CandidateSpec], and each candidate is not a one-liner but a skill document: recipe must fill five clauses, when → do → expect → verify → avoid, and verify must open with an [EXPLOIT]/[EXPLORE] direction tag and state “what counts as the confirming observation.”

04

The skill-DB record — a posterior on every piece of knowledge

skills/skill.py — @dataclass(slots=True, frozen=True) class Skill (fields, verbatim)

unfold source — Skill dataclass fields (skills/skill.py)
@dataclass(slots=True, frozen=True)
class Skill:
    skill_id: str                                  # stable UUID4
    summary: str                                   # one-line description
    recipe: str                                    # when->do->expect->verify->avoid
    evidence: list[str]                            # memory-id / trace quote refs
    posterior: tuple[int, int]                     # (confirm_n, falsify_n) Beta-style counts
    applicability_conditions: list[str]            # acting-time preconditions
    parent_hypothesis_ids: list[str]
    category: str                                  # mechanic|strategy|metacognitive|meta_skill|heuristic|invariant
    quarantined: bool = False
    quarantine_reason: str | None = None
    timestamp: datetime
    origin_task / origin_run_id                    # cross-game lineage tracking
    retrieval_labels: tuple[str, ...]              # searcher-vocabulary labels (T3)
    posterior_by_game: dict                        # per-game confirm/falsify split (T7)
    provenance: Provenance                         # scope ladder: level|game|family|universal

It round-trips as one JSONL line (to_record/from_record), and survival across the episode boundary is decided by a single pure predicate:

unfold source — the is_surviving() survival predicate (skills/skill.py)
def is_surviving(self, *, game: str | None = None) -> bool:
    # A skill survives the episode boundary iff:
    #   * not quarantined
    #   * confirm_n > falsify_n   (positive net evidence)
    #   * confirm_n + falsify_n >= 3   (minimum support; blocks one-shot promotion)
    c, f = post
    return (not self.quarantined) and (c > f) and (c + f >= 3)

Posterior updates happen only through Skills.confirm(skill_id_or_index, evidence_ref) / Skills.falsify(skill_id_or_index, reason, evidence_ref), and the moment falsify makes falsify_n > confirm_n the skill is auto-quarantined — quarantined, not deleted (source docstring, verbatim): “it is kept in the stack (so it can still surface as a cautionary anti-pattern) but flagged so callers do not reuse it as-is.”

input → output example (the shape of one to_record line)

unfold example — confirm() → the JSONL record shape
skills.confirm("3f2a...", evidence_ref="mem_a1b2c3d4")
# the record appended to skills.jsonl (abridged):
{"skill_id": "3f2a...", "summary": "...", "posterior": [3, 1],
 "posterior_by_game": {"ft09": [2, 0]}, "quarantined": false,
 "scope": "game", "provenance": {...}, "op": "confirm", ...}
05

compute_judge — scoring blocks and the fail-closed gate

skills/skill_judge.py — JudgeScore (excerpt) + the scoring blocks in scope/roles.py

unfold source — JudgeScore dataclass (skills/skill_judge.py)
@dataclass(frozen=True, slots=True)
class JudgeScore:
    advantage: float = 0.0    # 0..1 -- dIG(edit | library, memories, trace)
    grounding: float = 0.0    # 0..1 -- claims evidence-checked vs trace/memories
    combined: float = 0.0     # advantage x grounding, recomputed in __post_init__ (LLM-reported value ignored)
    weaknesses: str = ""      # single strongest doubt -- the miner's rewrite gradient (text)
    direction: dict = ...     # {mode: "exploit"|"explore", sign: +1|-1, ...} next-step direction

    def __post_init__(self):
        object.__setattr__(self, "combined",
            float(self.advantage) * float(self.grounding))

The judge is “one judge, two time axes” (the gist of the file docstring): inside a sleep it judges an edit’s expected information gain; across sleeps it judges memory-counterfactual necessity (“without that skill, would it have to be re-derived from the memories accumulated so far?”) — all without execution. The premise explicitly forbids scoring code: “you MUST NOT write or run scoring code — you ARE the score.”

Mode-conditioned scoring block (default: the novel-state proxy)

scope/roles.py — _NOVEL_STATE_SCORING (excerpt)

unfold source — the _NOVEL_STATE_SCORING block (scope/roles.py)
MODE-CONDITIONED SCORING -- advantage is PROGRESS-CONDITIONED on a CONCRETE
proxy: reaching a NOVEL (unseen) state. Stuck play has 0 level-ups, so a novel
state stands in for level progress; ...
  EXPLORE -- advantage means expected NEW information; weigh novelty above
    coverage; ... The probe earns HIGH advantage only when it is an
    untried move TOWARD a NOVEL (unseen) state ...
  EXPLOIT -- advantage means compression delivered; weigh coverage (how many
    observations it absorbs) above novelty; ... compressing a pattern
    that keeps the agent in the SAME state -- churn ... is LOW advantage
    no matter how consistent it is.

When A3_THEORIST_PROGRESS is on, this block is swapped for _HYPOTHESIS_PROGRESS_SCORING — advantage is redefined from “reaching a novel state” to “advancing / testing a theorist hypothesis present in the trace.” The block is selected in exactly one place, scoring_block(), so the in-sleep premise and the cross-sleep task always score by the same criterion (source comment: “No second copy of either block exists anywhere”).

The fail-closed commit rule

“a skill commits ONLY on a confident verdict (combined >= commit_conf). Every other outcome — low score, ‘pending’, or NO verdict (the judge timed out / errored …) — resolves WITHOUT committing. An unresolved spec is force-dropped at the horizon.” skill_judge.py docstring, verbatim

The sleep orchestrator is also barred from writing to the library directly: _SLEEP_SKILLS_READ_METHODS = frozenset({"summaries", "get", "query", "stack", "is_empty"}) — every mutator (add/rewrite/deprioritize/confirm/falsify) is blocked, and writes flow only through the commit_skill closure, which routes park → judge gate. (A sleep_phase.py comment records the origin of this block: in a real live run the LLM called skills.add directly and a 0.49 < τ edit entered the library.)

06

Multi-agent orchestration sketch

First line of the orchestrator premise (verbatim): “Coordinate subagents. You are a manager, not a player.” The orchestrator has no submit_action at all; instead it mints an action-budgeted counter via make_bounded_submit_action(limit) and hands it to subagents — the budget is attached to the function itself, so spawning sub-subagents does not reset it.

Arcgentica (agent.py) — wake/sleep driven by the same run_phase driver WakePhase: one step = one orchestrator .call (repeat until game clear / budget exhausted / no progress). SleepPhase: one step = one sleep-orchestrator pass
↓ wake: spawn_agent(system_prompt[, role]) + mandatory GAME_REFERENCE/history/memories hand-off
orchestration phases (the premise’s six steps, verbatim ordering) 1 Explore (explorer + bounded submit_action) → 2 Hypothesize (theorist, no submit_action) → 3 Test (targeted experiments on a small budget) → 4 Iterate (re-call the same theorist vs spawn a new one) → 5 Solve (solver) → 6 Next level (re-assess with a fresh explorer)
↓ shared by all agents
memories (add/summaries/query) + skills (the posterior-carrying library) Agent contexts die; memories/skills live the whole game. A pre-retirement “debrief” even recovers tacit knowledge
↻ sleep: the miner (skill_agent) proposes CandidateSpecs → compute_judge returns a JudgeScore → only combined ≥ commit_conf commits (generator ≠ evaluator)

The role registry (scope/roles.py) has exactly three live roles: skill_agent (miner) · compute_judge · theorist. explorer/tester/solver are not role constants but prompt-defined agents the orchestrator spawns with a free-form system_prompt. All three role premises end with the same line: “YOU MUST NOT call spawn_agent, submit_action, eval/exec/subprocess.”

07

What we adopted / what we did not

✓ adopted

  • The leak boundary (GAME_REFERENCE) — pinning “what the agent may know about the game” to a single constant document, with every experimental injection managed by an env gate plus a byte-identical default. Our engine’s prompt boundary inherits this design directly.
  • Hypothesis discipline — mechanism-based · absolute coordinates forbidden · one hypothesis = one falsifiable sentence naming its confirming observation · exhausted hypotheses marked. We adopted the THEORIST premise and GAME_REFERENCE’s “Forming good hypotheses” clause as the prose spec for our rule mining.

✗ not adopted

  • The multi-agent manager — the whole hierarchy where a “manager, not a player” orchestrator spawns explorer/theorist/tester/solver and allocates budgets. We keep a single code-native loop, and verification is engine-measured predict-verify on the game’s own logged transitions (with Game.fork sealed, fork_dependence = 0) rather than an LLM judge’s verdict.