veratown-prototype

Hierarchical Helper Bots — Implementation Proposal

Status: The initial helper control plane and location-scoped public Chat/Emote tasks are implemented. Optional, observed same-room startup teleport to an enabled point location is implemented; general movement and shared-map mutation remain out of scope. See the Helper Bots guide for runtime behavior and operator setup.

Executive decision

Run each BC account as an independently configured bot process. Keep one supervisor (the existing main bot) as the only authority that accepts operator requests and creates, assigns, cancels, and reviews helper tasks. Helpers execute only tasks assigned to their configured identity and may not delegate to peers or create child tasks.

Coordinate delegation through a durable, room-scoped MongoDB task queue in the database already selected by RUNTIME_TARGET. Each process owns exactly one BcClient, one Socket.IO connection, and that client’s existing outbound send queue. Do not put multiple clients in the main process or add a second transport path. Give each helper a dedicated BC account and deployment, but use the same BC server, room, and validated room-map revision when it is intended to appear on the same map.

This is a one-level hierarchy for the first release:

Operator / authorized room admin
                 │ requests
                 ▼
          Supervisor bot
       ┌─────────┼─────────┐
       ▼         ▼         ▼
    Helper A  Helper B  Helper C

Helpers can ask the supervisor for clarification or escalation. They cannot assign work to another helper, widen their own permissions, or treat peer messages as instructions.

Current architecture and scope

The implemented runtime has one statically composed BcClient and BcApiPlane; BcClient owns login, room join-or-create, observations, reconnection, and the 14-packet / 1,200 ms send queue. Its observations are server-driven, and the BC protocol has no general request ID for many state changes. See bot runtime architecture, BC API plane, and socket acknowledgement rules.

The map movement proposal documents the observed startup teleport slice and deferred graph movement. A helper may only use its operator-configured startup location; arbitrary task destinations are not accepted. A Mongo position record never proves that a character moved. Helper positioning is journaled and must be verified from BC observations.

Goals

Non-goals

Authority and interaction policy

Strict hierarchy

  1. The composition-root configuration declares one supervisor identity and an allowlist of helper identities. parentAgentId is immutable for a helper.
  2. Only the supervisor creates and assigns tasks. It authenticates the human requester under the existing command/room-admin policy, checks policy, then records a validated task envelope.
  3. A helper may claim only a queued task whose assignedAgentId matches its own configured identity. It may update progress/outcome for that task only.
  4. The helper’s effective permissions are the intersection of its static capability allowlist and the narrower capabilities, room, targets, and limits in the task. A task cannot grant a capability the helper was not configured to have.
  5. A helper cannot create tasks, change the agent registry, change its parent, assign work to another helper, or authorize its own escalation. A blocked task returns to the supervisor for a new decision.
  6. The supervisor cannot delegate authority it does not possess. Existing feature permission checks and dedicated BC actions still run at execution time; delegation is not an authorization bypass.
  7. The initial deployment is a flat tree: the supervisor is the only parent. Supporting deeper trees would require a separately reviewed protocol for immutable parent links, acyclic topology, capability attenuation, and bounded depth. It is not part of this proposal’s first release.

These are application-level controls for trusted runtime code, not a defense against an operator with direct database or BC-account credentials. If helpers must be isolated from each other’s database writes even when a helper is compromised, replace direct queue access with a separately authenticated supervisor control service before deployment; do not claim Mongo collection credentials provide document-level authorization.

Bot-to-bot interaction options

Option Appropriate use Limitations Decision
Durable Mongo task queue, polled by each helper Assignments, claims, progress, cancellation requests, results, and recovery Requires schema validation, compare-and-set transitions, leases, and target-database isolation Recommended control plane.
Supervisor-mediated BC whisper or room chat Human-visible notification that a task was assigned or completed BC chat has no reliable receipt acknowledgement; whispers may be hidden, delayed, or unavailable; content is not an authorization token Optional notification only. The durable task record remains authoritative.
Direct helper-to-helper BC messages None in the initial release Creates peer authority paths, duplicate command handling, ambiguous delivery, and no reliable request correlation Prohibited for control.
In-process worker objects Unit tests or later non-BC local work They are not separate BC accounts and must not create sockets; a local worker cannot stand in for a helper identity Not the helper deployment model.
External message broker or public HTTP API A future fleet-scale control plane Adds operational surface, credentials, dependencies, and another failure domain Defer; no need is established for the initial fleet.

The supervisor polls helper records and presents status through its existing authorized command surface. Helpers poll only their own assigned work. Poll intervals use bounded backoff and jitter; task claims use atomic compare-and-set updates so two processes cannot both claim the same queued task.

Runtime and BC/socket isolation

Each process uses the existing startup/configuration path with one dedicated BC account, one BcClient, one BcApiPlane, one ActionCoordinator, and one Mongo client for the fixed runtime target. A helper does not import or construct another bot’s client, and no feature touches socket.emit.

flowchart LR
    Operator[Authorized operator] --> Supervisor[Supervisor process]
    Supervisor -->|validated task records| Queue[(Helper task control plane)]
    HelperA[Helper A process] -->|claim / report| Queue
    HelperB[Helper B process] -->|claim / report| Queue
    Supervisor --> SClient[BcClient A<br/>one socket + local queue]
    HelperA --> AClient[BcClient B<br/>one socket + local queue]
    HelperB --> BClient[BcClient C<br/>one socket + local queue]
    SClient -->|BC protocol| BC[Bondage Club server<br/>shared room and map]
    AClient -->|BC protocol| BC
    BClient -->|BC protocol| BC
    SClient --> Journal[(prototypeActions)]
    AClient --> Journal
    BClient --> Journal
    Queue -. same fixed runtime database .- Journal

The diagram’s separate queues are intentional: each process retains the existing local rate limiter and request serialization. Do not reinterpret a response observed by one connection as an acknowledgement for another connection’s action. A task result and an action journal entry are separate records; the action outcome is determined by the executor’s own supported BC response or observation.

The local BcClient limiter is not evidence of a documented fleet-wide BC quota. Before enabling multiple accounts, qualify server limits with dedicated test accounts. If aggregate room traffic needs a cap, implement an optional fleet dispatch admission gate in the action path while retaining every local queue. It must fail closed when the gate is unavailable, never dispatch by raw Socket.IO, and never claim to enforce an undocumented server quota. Start with low per-helper action budgets and staggered polling.

Conflict ownership

Same-room locations and map authority

All agents configured for one coordinated map use the same validated roomKey, BC server, runtime target, and map configuration revision. Each dedicated BC account joins that room as a separate character. The supervisor may assign distinct logical locations to helpers, for example:

                    same BC room / same map revision
             ┌─────────────────────────────────────────┐
             │ north station: Supervisor              │
             │ west entrance: Helper A                │
             │ garden point: Helper B                 │
             └─────────────────────────────────────────┘

The BC room map (shared room objects/settings) is distinct from each character’s map position/state. Never represent one helper’s position by overwriting room map data. The bot’s latest valid BC sync remains authoritative; a task’s desired location, a stored location label, or a heartbeat is not proof of arrival. Logical location labels may map to BC coordinates only through the validated map/movement subsystem. If the movement action or matching BC observation is not available, report unsupported or unknown; do not simulate movement by patching snapshots or writing an authoritative-looking position document.

For independent positions, helpers may execute separate per-character movement tasks once movement support is implemented and qualified. For paths or shared location capacity, the supervisor validates the same room-map revision and occupancy policy before assignment, then rechecks immediately before the movement action. If configuration changes during a task, stop and reconcile against the new observed state rather than silently completing a stale route.

Control-plane records

Use collections in the currently selected fixed database only. Do not add a configurable database name or touch the source/legacy database.

prototypeHelperAgents

Validated, operator-managed records keyed by stable agentId:

Field Purpose
agentId Stable logical process identity; never a BC credential.
role supervisor or helper; exactly one supervisor per coordinated room.
parentAgentId null for the supervisor; supervisor ID for every v1 helper.
memberNumber Expected BC character identity, checked against the live account/room observation.
roomKey, runtimeTarget Scope the agent to one map and the existing test/production database pairing.
startLocationKey Optional enabled point location for observed same-room startup teleport only.
capabilities Reviewed allowlist of task types and permitted target scope.
enabled, maxActiveTasks Operator control and bounded concurrency; v1 default is one active task.

No password, Mongo URI, token, chat text, or arbitrary BC payload belongs in this document. Credentials remain in the deployment’s existing secret store. An agent whose live BC member number, room, or target does not match its configuration fails closed and cannot claim work.

prototypeHelperTasks

One validated record per delegation. Suggested fields:

taskId, parentAgentId, rootTaskId, assignedAgentId, createdByMemberNumber,
taskType, roomKey, mapRevision, targets, arguments, requiredCapabilities,
resourceKeys, status, createdAt, updatedAt, notBefore, expiresAt,
lease { ownerAgentId, epoch, leaseUntil }, cancellationRequestedAt,
resultCode, resultSummary, actionOperationIds

The task contains typed, bounded, allowlisted arguments rather than arbitrary BC packets or executable instructions. The envelope records the authority chain and intended scope. resultSummary is a redacted status summary only; it excludes secrets, private communications, full chat/whisper text, and appearance payloads. Do not store private message text in task arguments; delegated communications should use reviewed template identifiers or another approved, non-sensitive reference. Detailed evidence and lifecycle transitions remain in the existing prototypeActions journal owned by the executor.

Create and verify indexes before connecting agents:

Use atomic filters on taskId, expected status, assigned agent, lease epoch, and unexpired lease for each transition. Increment lease.epoch on a new claim to detect stale writers. Lease fencing protects task-record updates; it cannot retract a packet already sent to BC. Therefore an expired task that may have dispatched is reconciled, not automatically replayed.

Task and action outcomes are separate

Task control status describes delegation; ActionOutcome describes one BC operation. A successful task requires the result contract declared by its task type:

Do not convert a journal status, task transition, helper report, or chat echo into a stronger BC acknowledgement.

UML use-case overview

flowchart LR
    Operator((Authorized operator))
    Supervisor((Supervisor bot))
    Helper((Helper bot))
    BC((Bondage Club))
    DB[(Task control plane<br/>fixed runtime database)]

    subgraph System[Hierarchical helper-bot system]
        UC1([Request delegated task])
        UC2([Authorize and bound scope])
        UC3([Assign to configured helper])
        UC4([Claim and execute assigned task])
        UC5([Report progress and outcome])
        UC6([Cancel or escalate])
        UC7([Reconcile uncertain BC action])
        UC8([Observe helper presence and location])
        UC9([Review task and action audit])
    end

    Operator --> UC1
    Operator --> UC6
    Operator --> UC9
    Supervisor --> UC2
    Supervisor --> UC3
    Supervisor --> UC6
    Supervisor --> UC7
    Supervisor --> UC8
    Supervisor --> UC9
    Helper --> UC4
    Helper --> UC5
    Helper --> UC6
    Helper --> UC8
    BC --> UC4
    BC --> UC7
    UC3 --> DB
    UC4 --> DB
    UC5 --> DB
    UC6 --> DB
    UC7 --> DB
    UC9 --> DB

UML task state machine

stateDiagram-v2
    [*] --> queued: supervisor validates and assigns
    queued --> claimed: assigned helper atomically claims
    queued --> cancelled: supervisor cancels before claim
    queued --> expired: not claimed before expiry

    claimed --> running: helper validates lease, identity, room and capability
    claimed --> queued: helper exits before starting / lease safely released
    claimed --> cancelled: cancelled before any dispatch
    claimed --> expired: lease lost before start

    running --> cancel_requested: supervisor requests cancellation
    running --> awaiting_observation: BC packet dispatched; observation required
    running --> succeeded: task contract has definitive synchronous evidence
    running --> completed_unconfirmed: task contract permits dispatch-only result
    running --> failed: definitive validation or BC failure
    running --> cancelled: cancelled before dispatch
    running --> reconciliation_required: cancellation or lease loss after possible dispatch

    cancel_requested --> cancelled: helper confirms no dispatch occurred
    cancel_requested --> reconciliation_required: dispatch may have occurred

    awaiting_observation --> succeeded: matching supported observation/read-back
    awaiting_observation --> failed: definitive failure observed
    awaiting_observation --> reconciliation_required: timeout / process loss / ambiguous state

    reconciliation_required --> succeeded: supervisor confirms desired observed state
    reconciliation_required --> failed: supervisor confirms no effect or rejection
    reconciliation_required --> queued: supervisor approves safe, idempotent retry
    reconciliation_required --> cancelled: supervisor closes without replay

    succeeded --> [*]
    completed_unconfirmed --> [*]
    failed --> [*]
    cancelled --> [*]
    expired --> [*]

completed_unconfirmed is terminal but explicitly weaker than succeeded. Only the supervisor may resolve reconciliation_required; a helper cannot declare its own ambiguous action safe to retry. Transition history should preserve actor, timestamp, prior/new status, and a redacted reason.

UML helper-process lifecycle

stateDiagram-v2
    [*] --> starting
    starting --> connecting: config, DB and indexes validated
    starting --> fenced: identity, room or runtime target mismatch
    connecting --> ready: BC room sync and own member identity observed
    connecting --> degraded: connection or control-plane unavailable

    ready --> polling: poll interval reached
    polling --> ready: no eligible task
    polling --> claiming: eligible task found
    claiming --> executing: atomic claim and scope checks pass
    claiming --> ready: task already claimed or claim rejected
    executing --> reporting: task action returns outcome
    reporting --> ready: result stored under current lease
    executing --> degraded: lease lost / connection lost / ambiguous dispatch
    reporting --> fenced: stale lease cannot be renewed

    ready --> degraded: BC or control-plane disconnect
    degraded --> recovering: retry/backoff window reached
    recovering --> ready: identity and room revalidated
    recovering --> fenced: identity or scope no longer valid

    starting --> draining: shutdown requested
    connecting --> draining: shutdown requested
    ready --> draining: shutdown requested
    degraded --> draining: shutdown requested
    fenced --> draining: shutdown requested
    executing --> draining: shutdown requested
    reporting --> draining: shutdown requested
    draining --> reconciling: an action may have dispatched
    draining --> [*]: no in-flight action remains
    reconciling --> [*]: uncertain work persisted for supervisor review

fenced means the process stops claiming or dispatching; it is not an authorization to mutate another helper’s lease. Reconnection requires fresh account identity and room observations before task polling resumes.

Delegation sequence

sequenceDiagram
    actor Admin as Authorized operator
    participant Root as Supervisor bot
    participant Queue as prototypeHelperTasks
    participant Helper as Helper process
    participant Action as Helper ActionCoordinator
    participant BC as BC server

    Admin->>Root: request task (command)
    Root->>Root: authorize; check agent, room, capability, target and limits
    Root->>Queue: insert validated queued task
    Helper->>Queue: poll assigned tasks
    Helper->>Queue: atomic claim (agent ID + status + lease epoch)
    Queue-->>Helper: claimed task
    Helper->>Helper: validate config identity, lease, map revision and task scope
    Helper->>Action: execute dedicated action with taskId metadata
    Action->>BC: guarded packet via this helper's BcClient queue
    BC-->>Action: declared response and/or later state sync
    Action-->>Helper: honest ActionOutcome
    Helper->>Queue: CAS progress/final result under current lease
    Helper-->>Root: status becomes visible on next poll
    Root-->>Admin: report verified / unconfirmed / failed result

If the helper loses its lease or process connection after dispatch, it records or leaves the task in reconciliation_required; it does not resend the packet. If BC response semantics do not support a definitive result, the supervisor reports that uncertainty without upgrading the outcome.

Delivery phases

Phase 0 — Protocol and operator qualification

Phase 1 — Durable delegation, no new helper actions

Phase 2 — Bounded feature delegation

Phase 3 — Same-map positioning and coordinated behaviors

Verification and release criteria

Automated tests

Manual rollout gates

Principal risks and mitigations

Risk Mitigation
A helper interprets a task as authority to do more Strict typed task catalog, static capability intersection, fixed agent identity, target allowlists, execution-time policy checks.
Two bots process one command or task Supervisor-only command subscriptions; atomic task claim; assigned-agent filter and lease epoch.
Cross-socket action collision on shared BC state One writer for shared room resources; per-character ownership; serialize same-target work; no lease-expiry assumption for already-sent packets.
Fleet traffic exceeds server limits Retain each local BcClient limiter; test actual multi-account behavior; conservative budgets and optional fail-closed fleet admission.
Lost response causes duplicate non-idempotent action Explicit uncertain state, observation/reconciliation before any supervisor-approved safe retry.
Helper reports a false location BC sync is authority; task and heartbeat positions are telemetry only; don’t enable movement before the movement contract is qualified.
Helper credentials or logs leak private data Separate secret-store entries; no secrets in Mongo task documents, action metadata, logs, or chat-based control.
Helper process is compromised Separate BC accounts and deployments reduce blast radius; v1 assumes trusted runtime code. Use a separately authenticated control service if DB write isolation against a compromised helper is required.

Adopted first-release decisions

  1. Delegated communication and emote tasks use enabled, operator-managed public templates bound to a configured room location. A task succeeds only when the supervisor observes the matching message from the configured helper and its latest BC-observed position is within that location. Each helper is also a separate visible BC character, whose avatar is managed by the operator. Movement and literal shared-map roulette-wheel edits are not implemented.
  2. Production helpers may join the existing production room using dedicated BC accounts and the fixed production runtime database.
  3. The helper limit defaults to three and is database-configurable. Initial defaults are a five-second poll interval, five-minute task lifetime, and three dispatched actions per helper per minute; the settings document can tune these bounded values.
  4. Terminal task metadata and action-journal history have a maximum five-day retention. The oldest terminal records are pruned first after 10,000 records; active and reconciliation-required tasks are not evicted as terminal data.
  5. Status polling and /bot helpers commands are the primary operator surface. There is no additional supervisor-mediated BC notification channel.