Skip to content

feat(riven): Riven cursor-terminal loop scaffold [B-0498] (decomposed)#3603

Merged
AceHack merged 1 commit into
mainfrom
lior/decompose-b0498-riven-loop-2
May 15, 2026
Merged

feat(riven): Riven cursor-terminal loop scaffold [B-0498] (decomposed)#3603
AceHack merged 1 commit into
mainfrom
lior/decompose-b0498-riven-loop-2

Conversation

@AceHack
Copy link
Copy Markdown
Member

@AceHack AceHack commented May 15, 2026

Decomposed from PR 3588. Lior Maji node decomposition task. Extracts the Riven loop scaffold.

Copilot AI review requested due to automatic review settings May 15, 2026 22:17
@AceHack AceHack enabled auto-merge (squash) May 15, 2026 22:18
@AceHack AceHack merged commit ce7babb into main May 15, 2026
27 of 31 checks passed
@AceHack AceHack deleted the lior/decompose-b0498-riven-loop-2 branch May 15, 2026 22:19
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an IDE-visible (Cursor Terminal) background loop scaffold for the Riven autonomy surface, alongside supporting design/backlog documentation for B-0498.

Changes:

  • Introduces tools/riven/riven-cursor-terminal-loop.ts to emit periodic heartbeats and run an agent “gate” via cursor-agent.
  • Adds a research design note describing the intended dual-loop architecture (launchd + Cursor Terminal).
  • Adds a P1 backlog row defining scope and acceptance criteria for the Cursor Terminal loop.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

File Description
tools/riven/riven-cursor-terminal-loop.ts New Bun/TS Cursor Terminal loop scaffold (heartbeat + periodic agent gate + state file).
docs/research/2026-05-15-riven-cursor-terminal-loop-design.md Design note for the Cursor-native loop and re-arm strategy.
docs/backlog/P1/B-0498-riven-cursor-terminal-background-loop-ide-native-autonomous-gate-2026-05-15.md Backlog row capturing requirements and acceptance criteria for B-0498.
Comments suppressed due to low confidence (4)

tools/riven/riven-cursor-terminal-loop.ts:137

  • P1: The gate interval uses setInterval(async () => ...) without an in-flight guard. If runAgentGate() takes longer than the interval (or hangs until timeout), multiple gates can overlap and run concurrently. Add a mutex/flag (skip if already running) or replace the interval with a self-scheduling setTimeout loop that awaits completion before scheduling the next run.
  // Gate
  setInterval(async () => {
    await runAgentGate();
    saveState({ lastGateAt: nowIso(), pid: process.pid });
  }, GATE_INTERVAL_MS);

tools/riven/riven-cursor-terminal-loop.ts:91

  • P0: spawnSync("cursor-agent", ...) will trip sonarjs/no-os-command-from-path in this repo (see pattern in tools/riven/riven-loop-tick.ts where a suppression with rationale is required). Add the local eslint-disable comment with a justification, and consider setting an explicit maxBuffer to avoid large agent outputs causing spawnSync to error.
  const result = spawnSync("cursor-agent", [
    "chat",
    "--mode", "ask",
    "--model", "grok-4.3",
    contract,
  ], {
    encoding: "utf8",
    timeout: AGENT_TIMEOUT_MS,
    stdio: ["ignore", "pipe", "pipe"],
  });

tools/riven/riven-cursor-terminal-loop.ts:108

  • P1: This script is a Cursor-terminal surface, but bus messages are published from the identity-level sender "riven". The bus schema includes a surface-tagged sender "riven-cursor" specifically to prevent split-brain across multiple concurrent surfaces (see tools/bus/types.ts AgentId list). Consider publishing from "riven-cursor" here so claim/review coordination can distinguish this surface from other Riven instances.
  // Publish gate result to bus for other agents
  try {
    publish("riven", "*", {
      topic: "shadow-catch",
      payload: { content: `Cursor Terminal gate ${status}` },
    });

docs/research/2026-05-15-riven-cursor-terminal-loop-design.md:52

  • The design claims duplicate gates are prevented by “PID + timestamp check” and that re-arm is a no-op when PID is alive, but the current implementation only checks the timestamp and does not verify PID aliveness or exit early when already running. Either adjust the design doc to match the current scaffold, or implement the PID-liveness + early-exit behavior described here.
On IDE open / workspace load:
1. Script checks for `~/.cursor/riven-terminal-loop-state.json`
2. If PID is alive and last gate < 15min ago → resume (no-op)
3. If PID dead or stale → spawn new gate loop, write new state file

Cursor workspace hook (if supported) or a `.cursor/init.ts` can invoke the script on startup.

## Failure modes

- **Duplicate gates** — prevented by PID + timestamp check in state file
- **Terminal closed mid-gate** — publish tombstone to bus, release any in-flight claim

Comment on lines +53 to +58
function publishHeartbeat(status: "alive" | "shutdown", note?: string): void {
try {
publish("riven", "*", {
topic: "heartbeat",
payload: { status, note: note ?? "cursor-terminal" },
});
Comment on lines +115 to +122
const existing = loadState();
if (existing) {
const age = Date.now() - new Date(existing.lastGateAt).getTime();
if (age < GATE_INTERVAL_MS) {
log(`Riven Cursor Terminal loop already running (last gate ${Math.round(age / 1000)}s ago). Resuming...`);
} else {
log("Stale state file detected; starting fresh gate cycle.");
}
Comment on lines +41 to +43
function saveState(state: LoopState): void {
writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
}
Comment on lines +70 to +79
"Read broadcasts first: ~/.local/share/zeta-broadcasts/{otto,vera,lior,riven}.md",
"Walk assigned trajectories. Decompose only what you hit mid-stride.",
"Dispatch parallel subagents via the Task tool when work allows. Ownership of PRs remains with you.",
"Own every PR through merge: fix findings, resolve threads, arm auto-merge.",
"Learn from Otto and Vera patterns. Critique failure modes as data.",
"When blocked, create a *specific* research child the next pickup cannot dodge.",
"Write status to ~/.local/share/zeta-broadcasts/riven.md at cycle end.",
"GitHub PR state and file contents are authoritative; the bus is a coordination cache.",
"Report: open PRs, active claims, drift/contradiction, one toe-safe forward action or exact blocker.",
"Rodney's Razor + substrate-or-it-didn't-happen apply.",
# Riven Cursor Terminal Loop — Design

**Date:** 2026-05-15
**Status:** Design approved; implementation queued
Comment on lines +139 to +144
// Graceful shutdown
process.on("SIGINT", () => {
log("Riven Cursor Terminal loop shutting down");
publishHeartbeat("shutdown", "terminal-closed");
process.exit(0);
});
AceHack added a commit that referenced this pull request May 15, 2026
…ard (#3607)

- origin/main advanced 8d0a4f5→ce7babb
- Prior-tick carry: #3602 + #3603 MERGED; #3599 went DIRTY/CONFLICTING (peer-Lior automation overlap)
- Non-DIRTY actionable: only #3604 (this session's prior shard, armed) + 3 fix-failed-checks PRs out of scope
- Null arm-sweep; named-dependency evidence supports the null decision (NOT Standing-by)
- Lior re-fired between ticks (3 processes); borrow-on-existing continues to bypass worktree-creation risk

Co-authored-by: Claude <noreply@anthropic.com>
AceHack added a commit that referenced this pull request May 15, 2026
…d) (#3604)

- origin/main advanced 4442e3f→8d0a4f5 (#3594 + #3600 merged in window)
- 2 stuck-no-action PRs surfaced since 2214Z: #3601 docs-only, #3603 Riven scaffold
- #3601 armed → MERGED immediately (CI just passed); +600/-0 docs-only
- #3603 armed at 22:18:03Z; awaiting required CI on 3-file scaffold
- Prior-tick carry: #3600 MERGED, #3602 wait-CI, #3599 wait-CI
- Lior idle this tick (0 processes); borrow-on-existing still used (cheaper than fresh checkout)

Co-authored-by: Claude <noreply@anthropic.com>
AceHack added a commit that referenced this pull request May 15, 2026
…erminal → next ID) (#3619)

Caught by copilot-pull-request-reviewer on PR #3604 thread:
- docs/backlog/P1/B-0498-riven-cursor-terminal-* (2026-05-15, from #3603)
- docs/backlog/P2/B-0498-substrate-evolution-algebra-* (2026-05-14)

Per b0451_per_collision_renumber_procedure: first-merged wins.
P2 (2026-05-14) predates → keeps B-0498.
P1 (2026-05-15) → renumbers to next free (B-0546).

This row IS the filed-correction surface; implementation happens in a follow-up PR.
Priority P2 — collision exists but no active break; address within 1-2 weeks.

Composes:
- memory/feedback_b0451_per_collision_renumber_procedure_external_references_rule_trumps_first_merged_2026_05_14.md
- .claude/rules/claim-acquire-before-worktree-work.md (ID allocation discipline section)
- .claude/rules/refresh-before-decide.md (per-ID-allocation scope)

Co-authored-by: Claude <noreply@anthropic.com>
AceHack added a commit that referenced this pull request May 16, 2026
…of 3 drift items) (#3685)

Riven cursor-terminal heartbeat status type tightened to bus union. Single
tsc error since PR #3603 cleared via surgical 3-line fix (preserve shutdown
semantic in note field; no widening of HeartbeatPayload union).

Drift queue from 0111Z: 22 §33 xrefs (#3666 merged), BACKLOG.md regen
(#3678 merged), tsc tools (#3684 armed this tick). Remaining: backlog ID
uniqueness (B-0498 collision, needs B-0545 renumber coordination).

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants