Skip to content

Latest commit

 

History

History
170 lines (132 loc) · 5.45 KB

File metadata and controls

170 lines (132 loc) · 5.45 KB

Tick Protocol

English | Simplified Chinese

This document specifies the observable protocol implemented by @pulse-computing/dsh-tick-loop. It describes Harness behavior, not a theory of hidden model cognition.

Terms

  • Control command: /tick ..., consumed by the DSH command plane.
  • Time-step message: the ordinary user-role follow-up generated by the plugin. Its source identifies the plugin.
  • Natural context: at least one earlier user message whose source is user, followed by a durable terminal.
  • Terminal: the turn/end event for an ordinary model turn.
  • Run: one explicitly armed, bounded sequence using one frozen policy.
  • Policy: a named, immutable UTF-8 time-step text.

Command grammar

/tick [<count>] [--policy <id>] [--resume]
/tick policies
/tick status
/tick stop
  • count defaults to defaultTicks and must be in [1, 256].
  • policy defaults to defaultPolicyId.
  • Policy IDs start with an ASCII letter and contain at most 64 ASCII letters, digits, dots, underscores, or hyphens.
  • Policy text must be non-blank, well-formed Unicode and at most 4,096 UTF-8 bytes.
  • Unknown options, duplicated options, invalid counts, and unknown policies fail before a model-facing message is created.

/tick policies, /tick status, and /tick stop are control operations. They never become model input.

Message envelope

Every generated time-step message has this observable shape:

{
  "role": "user",
  "content": [{ "type": "text", "text": "tick" }],
  "source": {
    "kind": "plugin",
    "plugin": "@pulse-computing/dsh-tick-loop"
  }
}

The text may differ for a named policy. Historical counting uses source, not string equality. A human typing tick is therefore not counted as a plugin time step.

Run state machine

inactive
  | /tick and natural context has a completed terminal
  v
armed -- latest terminal missing --------------------------> waiting
  | latest terminal completed
  v
scheduled -- delay expires and state is still identical --> enqueued
  |                                                           |
  | state changed / disposed                                  | ordinary model turn
  v                                                           v
cancelled                                                terminal observed
                                                              |
                     +----------------------------------------+
                     | completed and remaining > 0 -> scheduled
                     | completed and remaining = 0 -> complete
                     | error/unknown/inconsistent -> stopped

Only one timer and one run may exist per live Agent object. The timer rechecks the complete scheduling predicate before enqueue. An active turn is never steered.

Scheduling predicates

A new run is admitted only when:

  1. at least one natural user message exists;
  2. a latest closed turn exists;
  3. the latest terminal is completed, except for the explicit recovery case;
  4. no other Tick run is active for that Agent;
  5. the selected policy exists and is valid.

The next message is scheduled only when:

  1. the observed plugin time-step count is between the run's frozen start and target counts;
  2. the latest turn has a durable terminal;
  3. that terminal is completed, or it is the single exact interrupted boundary authorized by --resume;
  4. fewer than the requested number of additional messages have been observed.

The scheduler does not infer success from assistant text, elapsed time, or provider transport state.

Policy freezing

At plugin startup, every configured policy is compiled to:

{
  "id": "reflective-en",
  "timeStepText": "...",
  "timeStepBytes": 143,
  "timeStepSha256": "..."
}

The value is immutable. A run captures exactly one compiled policy. Mutating the original configuration object cannot change a later step in that run.

Audit ledger

The default directory is .pulse-tick-audit under the DSH process working directory. Each session has one append-only JSONL file whose name is sanitized from the session ID.

All records use schema pulse.tick-loop.audit.v1 and include recordedAt, sessionId, runId, policyId, timeStepSha256, and timeStepBytes where applicable.

Record types:

  • loop_armed
  • tick_scheduled
  • tick_enqueued
  • tick_terminal
  • tick_cancelled_before_enqueue
  • loop_stopped
  • loop_complete

The audit is an operational trace, not an immutable or independently signed scientific ledger. Protect it like session metadata and do not publish it without reviewing paths, timestamps, provider data, and workspace details.

Interruption and recovery

Without --resume, any latest non-completed terminal rejects or stops the run. With --resume, the latest terminal may be exactly interrupted. That boundary is allowed once, before the first new message of the new run.

This does not:

  • restore an old in-memory run ID or timer;
  • count the interrupted turn as completed;
  • replay an earlier tool call;
  • claim that an unknown side effect did or did not happen.

Deliberate non-features

  • no unbounded or infinite run;
  • no ordinary-conversation auto-start;
  • no goal, persona, or purpose injection;
  • no active-turn steering;
  • no timer-based retry;
  • no silent switch to Goal, Ralph, compaction, or another loop;
  • no claim that a terminal turn contains useful thought.

These constraints keep Tick a separable experimental primitive.