Skip to content

Developer contribution map and protocol entrypoints

Contributing to LoopX does not only mean changing the Kernel, and it does not only mean building an Extension. External developers can improve control-plane rules, Capabilities and Domain State, Providers, Hosts and Runners, projections and dashboards, documentation and fixtures, or independently distributed packages. The first decision is not a directory. It is the outcome you intend to ship and the contract that owns it.

The easiest wrong way to read LoopX source is to open the largest Python module and follow function calls until the behavior feels familiar. That reveals implementation, but not why the behavior exists or which consumers must remain compatible after a change.

External contributors need a more durable route:

text
developer job
  -> contribution outcome and placement
  -> protocol family
  -> invariant owned by that protocol
  -> bounded context
  -> current implementation and validation

This chapter is a protocol-first source map. It is not a complete API catalog, and it does not ask you to memorize current function names. Its job is to help you identify the contract your Issue or PR will change.

What you should learn

After this chapter, you should be able to:

  • decide whether a contribution belongs to the Control Plane, a Capability, a Provider, a Host or Runner, a projection or documentation surface, or Extension lifecycle;
  • record the capability id, provider id, and built-in or extension-delivered placement;
  • place protocol work in the state, work-graph, Turn/Host, or evidence family;
  • distinguish a canonical contract, read model, Host adapter, and renderer;
  • choose a bounded context by change reason instead of filename;
  • turn a public contributor task or Issue into a reviewable slice;
  • describe a change with protocols, invariants, and evidence rather than a function inventory.

Write a protocol card before reading code

Start with a short card:

text
Reader-visible problem:
Current protocol:
Source of truth:
Invariant at risk:
Allowed transition:
Forbidden outcome:
Expected receipt:
Validation surface:

Suppose a nonblocking user notice incorrectly grants publication authority:

text
Current protocol: decision_scope_v0
Source of truth: typed Gate and Todo requirements
Invariant at risk: a notice cannot grant authority
Allowed transition: a matching approved Gate consumes only covered scope
Forbidden outcome: an unrelated or nonblocking notice unblocks publication
Expected receipt: linked decision and lifecycle event
Validation surface: decision table plus quota integration smoke

This card is more useful than “I will modify quota.py.” Files can move. The contract and forbidden outcome remain reviewable.

Choose the contribution outcome and placement first

Before implementation, record four placement facts:

text
Capability id:
Provider id:
Delivery: built-in | extension-delivered | standalone package
Why the nearest existing owner is or is not sufficient:

Then choose the contribution surface from the caller-visible outcome:

SurfaceContract it ownsTypical deliveryMust not acquire incidentally
Kernel / Control PlaneGeneric Goal, Todo, Gate, quota, scheduler, and lifecycle invariantsTyped transition, decision rule, recovery repairAll state for one business domain
Capability / Domain StateCaller-facing outcome, domain policy, and result lifecycleDomain command, typed result, admission or read modelProvider credentials or a duplicate control plane
Provider / external systemBounded request, external call, observation, effect, and readbackBuilt-in or extension-delivered implementationGoal authority, completion judgment, or replacement service authentication
Host / Runner / Session RuntimeTyped execution, visibility, resume handles, and Host-owned effectsHost adapter, Runner, scheduler-owner integrationLoopX canonical state or self-validated completion
Projection / Dashboard / Docs / fixturesReader-facing models, explanation, and public-safe evidenceCLI renderer, dashboard, protocol documentation, synthetic fixtureBrowser write authority or another state machine
Extension / package lifecycleIndependent install, activation, doctor, upgrade, rollback, and compatibilityStandalone package or a Capability Provider delivery unitCapability domain policy or automatic authority

These surfaces can compose without collapsing into a generic “plugin”:

  • define a Capability and Domain State when you introduce a stable caller result, then choose a core or Extension-delivered Provider;
  • preserve an existing Capability when only the external service implementation changes, and add a Provider with the appropriate lifecycle;
  • build an operator dashboard from public-safe projections rather than parsing private project files or inventing a browser write path;
  • keep Host continuation on the existing quota, scheduler, and Turn contracts instead of adding another scheduler inside a Runner;
  • use a standalone Extension for a deterministic, zero-permission command without inventing a fake Capability.

A new module, CLI option, or schema needs a real caller, active call site, or explicit compatibility contract. Keep hypothetical Providers, Runners, and projections in design or Todo state until the shipped path exists.

Five core protocol families

The protocol directory grows with the product. External contributors do not need to read it alphabetically. Choose a family from the job you are doing.

1. State and projection

This family answers:

Where does a fact live, who may write it, and how is it reconstructed for readers?

Start with:

Typical jobs:

  • status and the event ledger disagree;
  • the active-state parser drops a field;
  • the task graph loses lineage or truncation diagnostics;
  • retry duplicates a lifecycle effect;
  • a dashboard needs another field.

The dashboard example begins with “which source owns this field?” It does not begin with a new editable UI state.

2. Work graph, authority, and peers

This family answers:

Who may perform which work now, what blocks it, and who continues afterward?

Start with:

Typical jobs:

  • one Gate freezes every Agent;
  • a claim is treated as a lock or global authority;
  • a handoff completes without a successor;
  • monitor and advancement precedence is wrong;
  • a Host can execute an action but lacks the required decision scope.

Review authority first and implementation branches second. Words such as approved, owner, or waiting for user do not replace a typed scope relation.

3. Quota, interaction, and scheduling

This family answers:

How are complex facts compiled into user, Agent, and CLI responsibilities for this turn?

Start with:

The core contract is not one should_run boolean:

text
source facts
  -> normalized projections
  -> ordered policy
  -> interaction_contract
  -> scheduler_hint

A user Gate can require a user response while the Agent channel still requires independent safe work. Collapsing both channels into a boolean damages interaction and scheduling at the same time.

4. Bounded Turn and Host effects

This family answers:

How is one external action proposed, executed, independently validated, and written back?

Start with:

Keep three responsibilities separate:

ResponsibilityOwnerMust not be replaced by
Select the current actionLoopX control planeHost inference from status prose
Execute a bounded effectHost adapterLoopX pretending an external action occurred
Judge the postconditionIndependent validatorThe Host's natural-language success claim

A session handle, raw stdout, or transcript can help Host recovery. It cannot become Goal authority or completion proof.

5. Evidence, recovery, and quality

This family answers:

How do we prove a rule, recover from failure, and bind receipts to the current revision?

Start with:

Quality is not a final testing appendix. The protocol card's forbidden outcomes and expected receipt should determine the validation design before implementation.

Map a protocol family to a bounded context

Protocols define cross-module contracts. Bounded contexts identify which change reason owns implementation:

ContextPrimary responsibility
goalsGoal state, Vision, Goal-level planning, and frontier
todosTodo lifecycle, scope, resume, monitor, and handoff summaries
agentsAgent identity, Agent-scoped routing, and capability
quotaCompile projected facts into the current interaction decision
schedulerCadence, backoff, reset, and acknowledgement
runtimeTurn/session projection and bounded execution state
handoffCross-runtime handoff, review packets, and owner routes
work_itemsAttention, selection, and operator-facing work read models

Ask:

text
What reason would cause this rule to change?

Do not ask:

text
Which current file already reads a similar field?

For example:

  • Gate coverage belongs to the authority and Todo contract;
  • rendering an arbitrated result belongs to a projection or renderer;
  • wake-up timing belongs to the scheduler;
  • applying one effect belongs to a Host adapter;
  • deciding acceptance belongs to a validator.

One PR may touch several contexts, but every change should serve one coherent protocol chain.

Map the contribution surface to a repository owner

Treat repository routes as owners, not as automatic placement from a directory name:

OutcomeLook here first
Generic control-plane ruleloopx/control_plane/<bounded-context>/ and the owning protocol or decision table
Existing Capability result or Domain Stateloopx/capabilities/<capability>/
Capability and Provider registrationloopx/capabilities/registry.py, catalogs, and manifest contracts
Generic Extension manifest, readiness, and runtimeloopx/extensions/
Independently installed packagepackages/<package-id>/ or a separate repository
Host or Runner integrationRuntime connector, Turn and Host contracts, and the matching adapter
Operator projectionStatus, frontstage, or projection owner; a renderer only consumes the typed model
Documentation and validationOwning protocol document, tests/, examples/, or a public-safe fixture

Code under loopx/capabilities/<name>/ is not automatically a public Capability; it still needs explicit registration and a real caller contract. loopx/extensions/ is not a bucket for every external integration; it owns generic Extension lifecycle, while an independently versioned Provider belongs in its delivery package. Keep private helpers with the nearest owner instead of promoting them to a Capability or Extension merely because they span several files.

Function names are search anchors, not the curriculum

The official maintainer course and source provide current implementation anchors. Use them with three rules:

  1. Read the protocol and decision table before searching for an implementation anchor.
  2. Confirm that the symbol still owns the same input, output, and invariant.
  3. Cite the contract and invariant in a PR; use symbol names only to help reviewers navigate the diff.

In the current source, you may begin from a quota-decision builder, Turn driver, or task-graph builder. Those anchors can move into better bounded contexts. Your mental model should survive the move.

If a document needs twenty function names to explain one behavior, it is probably copying implementation instead of teaching the protocol.

Choose a public contribution entrypoint

Do not infer public work from maintainer-local state. Use public surfaces:

  1. Read CONTRIBUTOR_TASKS.md.
  2. Choose a Starter, Focused, or already-agreed design task.
  3. Read the protocols and validation named by that task.
  4. State the smallest intended slice in the linked Issue.
  5. Wait for maintainer direction before a large or behavior-changing implementation.
  6. Deliver one independently reviewable and reversible protocol result on a clean branch.

Do not create public tasks from:

  • .loopx/, .codex/goals/, or live active state;
  • private benchmark traces, raw Agent sessions, or verifier output;
  • internal documents, production credentials, or machine paths;
  • speculative duplication of maintainer-owned live runs.

Public contributions build context from public-safe protocols, Issues, and fixtures.

Contributions do not have to change runtime code. Public tasks can also deliver:

  • protocol documentation, migration notes, and contributor walkthroughs;
  • deterministic decision tables, negative tests, and public-safe replay fixtures;
  • read-only dashboards, accessibility improvements, and operator explanations;
  • fake-Host, fake-Provider, and no-sink integration examples;
  • Extension scaffolds, manifest compatibility, and lifecycle smokes.

For every artifact, state the reader-visible result, the authority that maintains the fact, and the event that makes the document, fixture, or compatibility claim stale.

Decide whether the slice is right-sized

A coherent slice can usually be described as one protocol result:

Make decision_scope_v0 select typed repair when scope relations are missing instead of treating the Gate as global authority.

This is usually too broad:

Refactor status, quota, scheduler, and every test.

Right-sizing is not only reducing line count. Preserve one complete causal chain:

text
source
  -> invariant
  -> decision
  -> projection or effect
  -> receipt
  -> validation

Do not submit only a helper in the middle of the chain. Do not add speculative enums, CLI flags, or adapters without a real call site.

Checklist

Before entering the source, confirm:

  • [ ] Which contribution surface and caller outcome does this work serve?
  • [ ] What are the capability id, provider id, and delivery placement when they apply?
  • [ ] Which protocol family owns the problem?
  • [ ] What are the canonical source and primary writer?
  • [ ] Which invariant is at risk?
  • [ ] What are the legal and forbidden transitions?
  • [ ] Which bounded context owns the change reason?
  • [ ] Which public fixture or smoke proves the shipped path?
  • [ ] Is the task public and claimable rather than maintainer-owned live work?
  • [ ] Can the PR be described as one complete protocol result?

The next chapter traces one scoped-Gate scenario through source, projection, decision, Turn, receipt, and fresh replay.