Prior Work Deep-Dive · grounded in source code
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.
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.
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):
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.
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.
scope/roles.py — _THEORIST_PREMISE (full text)
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.”
scope/roles.py — _SKILL_AGENT_PREMISE, excerpt
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.”
skills/skill.py — @dataclass(slots=True, frozen=True) class Skill (fields, verbatim)
@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:
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)
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", ...}
skills/skill_judge.py — JudgeScore (excerpt) + the scoring blocks in scope/roles.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.”
scope/roles.py — _NOVEL_STATE_SCORING (excerpt)
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”).
“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.)
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.
.call (repeat until game clear / budget exhausted / no progress). SleepPhase: one step = one sleep-orchestrator passThe 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.”
Game.fork sealed, fork_dependence = 0) rather
than an LLM judge’s verdict.