Steadmesh

Composable native teams

Keep a declared leadership group, add a bounded pool of independent teammates, and let those teammates organise work on an explicitly shared board. Coordination, membership, permissions and editable context are separate choices.

Version requirement: these policies require v0.7.0 or matching provider, controller, platform and seat images built from this source tree. Check published releases before using release artifacts, and follow the v0.7.0 upgrade instructions for an existing deployment. The examples below use the local source setup.

Choose a team shape

A native team composes three optional policies:

Static seats continue to use ordinary teams memberships. Runtime pool members use independent seat identities; Terraform owns their policy and bounds, not a changing list of runtime identities. A self-organising team can use only declared seats, only a pool, or both.

teams = {
  delivery = {
    coordination = {
      mode                       = "self_organising"
      mission                    = "Produce a reviewed project plan."
      work_store                 = "board"
      mission_editors            = ["team:delivery"]
      review_policy              = "required"
      max_messages_per_execution = 20
    }
    context = {
      editable_instructions = false
      editable_summary      = true
    }
    # Add pool = { ... } to admit dynamic members.
  }
}

This excerpt is policy only. The complete examples also declare the board, grants, message routes, harness/execution/sandbox profiles, role bundles, budgets and pool templates.

Independent participants

Every admitted native member has its own identity, inbox, ordinary turn lifecycle and private memory. It uses the normal seat runner and tools under the operator-declared template. It does not borrow its requester's active execution, lease, read-only tool subset or private memory. A member can collaborate across ordinary turns rather than disappearing when its requester's turn ends.

Declare a full seat inside each pool template, including its role reference and harness, execution and sandbox profiles. Team membership and explicit grants determine authority in the same way as for other seats. Do not supply a shared fixed personal_memory or adopt_from in a pool template; each member needs its own private identity and memory. The owning pool team is added to membership automatically.

Authority and review

The operator's permission envelope stays authoritative. A mission, a title such as CEO, an editable prompt or a teammate's request cannot add connections, grants, sandbox access, routes or pool capacity. The original task remains available; self-edits are subordinate working context and never replace it.

work_store must name a declared shared memory store with explicit team read, write and revise authority. Naming the store is not a grant. Keep search, history or other operations explicit too. Personal memory remains private unless its owner deliberately publishes permitted information.

mission_editors authorizes mission edits only. Use seat:member_key for selected declared members or team:delivery for all members of that team. An empty list authorizes no agent edits. Neither selector grants additional tools or message access. To refine a mission, read teams.mission and supply both its numeric revision as expected_revision and mission.policy_revision as expected_policy_revision to teams.refine_mission, along with the mission and reason. Operator policy changes invalidate stale refinements.

review_policy = "required" makes review a distinct step before accepted completion. Assignment, execution success and business acceptance are different facts. work.review requires a distinct owner and reviewer, in-review status and evidence for approval. Changes to the objective, acceptance criteria, plan, owner or evidence invalidate the approval; incidental notes do not. work.refine lets explicit mission editors revise current objectives with a reason while retaining the original task in revision history. Set clear reviewer responsibilities in the mission and role instructions; there is no implicit privileged reviewer or executive. Use a separate participant for review and retain evidence on the board.

Direct messages always require an operator-declared route. Shared membership alone does not permit messaging. This explicit peer route allows members of delivery to communicate:

message_routes = {
  delivery_peers = {
    from          = "team:delivery"
    to            = "team:delivery"
    bidirectional = true
  }
}

Apply positive organisation and execution output-token budgets before enabling a pool. Message limits require an active execution and include outgoing sends and replies. Pool bounds, message limits and model budgets limit different resources; none replaces the others. See model output budgets.

Context and memory are independent

editable_instructions controls self-authored working instructions. editable_summary controls a compact private summary. Both default to false. Normal memory access still follows the seat's personal-memory ownership and explicit shared-memory grants, independently of those flags.

Choose one of three instruction behaviours: immutable (editable_instructions = false), direct self-edit (editable_instructions = true) or reviewed edits (also set require_instruction_approval = true and explicit instruction_approvers). The hybrid example uses reviewed edits with the three named leaders as approvers. An author cannot approve their own proposal; a leader needs another authorized leader. Across memberships, any approval requirement overrides direct self-edit, and explicit approver selectors are combined. Approval grants no access to the author’s private summary or memory.

The fixed-prompts example disables instruction edits but permits summary edits and ordinary memory writes. To freeze both context fields while keeping memory writable, set both flags to false and leave the memory grants unchanged. To make shared memory read-only, change those grants; an instruction flag does not do it.

Within an authenticated active seat turn, context.read returns current context or a selected revision. context.update changes one field using mandatory compare-and-swap expected_revision. When approval is required, instruction updates and instruction rollback must use the reviewed proposal workflow; direct writes are refused. Summary updates keep their independent permission. An untouched context starts at revision 0. Each field is limited to 4096 UTF-8 bytes, with combined JSON-escaped fields capped at 14336 bytes.

steadmesh-tools call context.read '{}'
steadmesh-tools call context.update '{"field":"summary","text":"Plan drafted; awaiting independent review.","expected_revision":0}'
steadmesh-tools call context.update '{"field":"summary","text":"Review complete; preparing delivery.","expected_revision":1}'
steadmesh-tools call context.history '{}'
steadmesh-tools call context.rollback '{"field":"summary","revision":1,"expected_revision":2}'

Use the revision actually returned by your read; the values above illustrate two initial updates and restoring the first saved snapshot. Revision 0 describes an empty initial context, not a saved rollback target. Rollback requires an existing revision of at least 1. Rollback restores only the selected, permitted field and creates a new revision. History returns the latest 20 revision metadata entries; pass before_revision to page backward. These tools target only the authenticated participant, never a supplied teammate identity. Changes become visible on the next ordinary turn, including resumed native harness sessions.

Review an instruction change

With approval required, the author calls context.propose_instruction with text, expected_context_revision and a reason. This creates a proposal, not a context update. Read the current revision first; private summary changes also advance context revisions.

Use context.proposals to inspect your own proposals or pending proposals you are explicitly authorized to review as a member of the same team. Results contain one proposal per page; pass next_before_sequence as before_sequence for the next page. Reviewers receive the proposed instructions, not access to the author’s private summary or memory.

A different authorized participant calls context.approve_instruction with the proposal’s exact proposal_id, expected_context_revision, policy_token and approve boolean. Self-approval is always refused, including when the whole team is an approver. Approval appends a revision attributed to both author and approver, visible on the author’s next turn; rejection leaves context unchanged. If context or approval policy has changed, the proposal is stale and must be proposed again.

Availability, draining and retention

min_members = 3 means keep three members available for work. It does not mean three models constantly generating output. The ordinary inbox and execution idle policy decide when each member runs; the pool's idle timeout decides when surplus members can retire. max_members = 30 bounds admitted pool members, not every static seat in the organisation.

Set draining = true to stop admitting new members and drain the pool. Draining gives active participants a bounded opportunity to finish and leave a handoff. A drain timeout bounds that opportunity; it does not establish business completion. Handoffs, execution history and private memory survive draining. With retention_seconds = 0 (the default), private records remain indefinitely. A positive value explicitly opts into automatic cleanup after retirement plus that interval: retired-private context, memory, session and handoff data are removed. Shared evidence and message audit are retained. This is a destructive data-retention choice; choose it deliberately before applying the policy. Retention is not permission to make private memory visible to teammates.

Native pool defaults are min_members = 0, idle timeout 900 seconds, drain timeout 300 seconds and retention_seconds = 0 (indefinite). Supply max_members and at least one explicit template. Baseline minimum membership uses the alphabetically first template; request other configured templates explicitly through teams.grow. Keep organisation/store data-retention choices aligned with operational and privacy needs; do not assume retirement deletes every retained record immediately.

Run three complete local examples

Each root includes complete HCL, a local role bundle, a deterministic fake-harness smoke input and setup instructions. Reuse the foundation/platform stages, the locally built provider and a local terminal credential fixture. No model API key, Slack account or live external service is required. Initial dependency/image downloads still need network access; cached provider and container artifacts allow subsequent offline fixture runs.

The fake harness executes explicit script commands; it does not invent a real project plan or demonstrate model-driven autonomy. Its smoke input checks the terminal-to-seat turn path. Inspect runtime membership and use the integration tests for lifecycle and authorization coverage.

Backwards-compatible defaults and separate legacy mode

Omitting these native policies preserves existing declared-team behaviour. A supplied coordination block defaults to mode = "declared", review_policy = "none" and a maximum of 20 messages per execution. No pool is created by omission; context edit permissions remain off.

Disposable task workers and legacy elastic_teams remain separate execution-scoped mechanisms. Their read-only worker authority, inheritance and cleanup rules still apply. A legacy worker is not a native member, and existing task records or worker policies are not automatically migrated. Choose a native pool explicitly when independent ongoing participants are the intended model.