Active Threads
March 29, 2026 · View on GitHub
Purpose
Active Threads is a plant-local protocol for keeping current work legible
without expanding MEMORY.md into a fragile run-by-run narrative.
The canonical artifact lives at:
plants/<plant>/memory/active-threads.json
It is intended to answer, from one file:
- what threads are active now
- how those threads relate
- what changed recently
Schema
See schema/active-threads.schema.json.
Top-level required fields:
schema_versioncaptured_atcaptured_by_runplantsummarythreadsrecent_updates
Thread fields
Each thread records:
idtitlestateprioritylast_changed_atsummarycurrent_focusnext_steprelated_thread_idsevidence
state is one of:
activenear_donewatchingblocked
priority is one of:
primarysecondarybackground
Recent update fields
Each recent update records:
tssummarythread_idsevidence
Boundary
The supported write boundary is:
from system.active_threads import write_active_threads
That helper validates the candidate artifact via:
from system.validate import validate_active_threads
and then:
- emits
ActiveThreadsRefreshStartedto<runtime-root>/events/coordinator.jsonl - validates the candidate artifact
- writes
plants/<plant>/memory/active-threads.jsonon success - emits
ActiveThreadsRefreshFinishedwith the refresh outcome
Read helpers:
from system.active_threads import read_active_threads, active_threads_path
Update rules
Keep the file small and current.
Refresh it when:
- a bounded review closes, reopens, or narrows a thread
- one thread spawns or absorbs another thread
- a conversation-origin request creates a new durable aim
- you need to answer a state/progress question without rereading scattered records
Recommended maintenance rules:
- track only live or near-live work
- allow
recent_updatesto keep a just-closed thread id briefly after that thread leavesthreads - keep
recent_updatescompact and newest-first - record relations explicitly rather than implying them in prose
- keep
MEMORY.mdfor durable identity, policy, and long-lived learnings - use
active-threads.jsonfor current focus and recent change tracking
Refresh event surface
Ordinary helper-driven refreshes now emit one bounded event pair in
<runtime-root>/events/coordinator.jsonl:
ActiveThreadsRefreshStartedActiveThreadsRefreshFinished
Required event fields:
- started:
plant,active_threads_path - finished:
plant,active_threads_path,active_threads_outcome
Optional event metadata:
goal/runwhen the refresh happens inside a normal run contextactive_threads_reasonplusdetailwhen the finish outcome is notsuccess
Current active_threads_outcome values:
successvalidation_rejectedio_error
Seed/template inheritance
Future gardens inherit the protocol through seed-local gardener assets in:
seeds/gardener/skills/active-threads.mdseeds/gardener/knowledge/active-thread-protocol.md
The current inheritance path is shared with the general seeded-plant flow:
system.plants.commission_seeded_plant()is the ordinary bootstrap path. It commissions the plant and then callssystem.plants.materialize_seed_context()to writeplants/<plant>/seedplus copy seed-localskills/andknowledge/intoplants/<plant>/.system.genesis.genesis()uses that seeded commissioning helper for a fresh gardener bootstrap. If the gardener record already exists, genesis refreshes the same seed context by callingsystem.plants.materialize_seed_context()directly before continuing.
That shared path is why the protocol is available in new gardens without hand-recreating it.
Failure modes
validate_active_threads() and write_active_threads() surface these named
rejections:
INVALID_ACTIVE_THREADS_SHAPEUNKNOWN_ACTIVE_THREADS_FIELDMISSING_REQUIRED_FIELDINVALID_ACTIVE_THREADS_SCHEMA_VERSIONINVALID_TIMESTAMPINVALID_ACTIVE_THREADS_RUNINVALID_ACTIVE_THREADS_PLANTEMPTY_ACTIVE_THREADS_SUMMARYINVALID_ACTIVE_THREADS_THREADUNKNOWN_ACTIVE_THREADS_THREAD_FIELDINVALID_ACTIVE_THREADS_THREAD_IDDUPLICATE_ACTIVE_THREAD_IDEMPTY_ACTIVE_THREADS_THREAD_FIELDINVALID_ACTIVE_THREADS_THREAD_STATEINVALID_ACTIVE_THREADS_THREAD_PRIORITYINVALID_ACTIVE_THREADS_THREAD_RELATIONINVALID_ACTIVE_THREADS_THREAD_EVIDENCESELF_REFERENTIAL_ACTIVE_THREADUNKNOWN_ACTIVE_THREAD_RELATIONINVALID_ACTIVE_THREADS_UPDATEUNKNOWN_ACTIVE_THREADS_UPDATE_FIELDEMPTY_ACTIVE_THREADS_UPDATE_SUMMARYINVALID_ACTIVE_THREADS_UPDATE_THREAD_IDSINVALID_ACTIVE_THREADS_UPDATE_EVIDENCEIO_ERROR
Verification
Focused coverage lives in:
tests/test_active_threads.pytests/test_genesis.pytests/test_plants.pytests/test_cli_init.py
tests/test_active_threads.py covers the happy path plus each named Active
Threads rejection code, including the ordinary refresh start/finish event
surface. tests/test_plants.py covers seeded commissioning writing the seed
reference plus copied skills/knowledge, and tests/test_genesis.py covers the
direct seed-context materialization and bootstrap behavior used at garden
startup.