Skip to main content

Tutorial: go dormant, then opt a session back in

ContextRelay ships auto-connect on: every Claude Code session in a project with a managed instruction block engages the collaboration loop. That is the right default when you pair Claude and Codex regularly. But plenty of developers run Claude Code solo most of the time and only want ContextRelay for a handful of specific sessions.

This tutorial walks the full dormancy lifecycle: make ContextRelay quiet by default for your user, confirm nothing surfaces in a fresh session, opt one workspace back in on demand, verify it is active, then leave again - all without touching the project's committed config or your peer's setup.

Who this is for

A developer who wants ContextRelay off unless asked for. If you instead want it on everywhere (the shipped behavior), you do not need any of this - just start your pair. See Activation: auto-connect vs dormant for the full model.

The principle: an explicit precedence chain

Everything below is governed by one deterministic resolver (resolveActivation in src/activation.ts). When a hook or the CLI asks "is ContextRelay active for this session?", the answer is decided top-down by the first rule that matches:

  1. Env override - CONTEXTRELAY_AUTO_CONNECT=1/0 wins over everything, for that one invocation.
  2. Per-session attach marker - a marker file for this workspace forces active.
  3. Project flag - activation.autoConnect in the project's .contextrelay/config.json, if set.
  4. Global flag - autoConnect in ~/.contextrelay/activation.json, if set.
  5. Shipped default - active (auto-connect on). This is why doing nothing keeps it on.

Going dormant means writing rule 4 (global flag = off). Opting a session back in means writing rule 2 (the attach marker), which beats the global flag. Keep that order in mind - every step is just nudging one tier of this chain.

Prerequisites

  • ContextRelay installed (@proofofwork-agency/contextrelay) and init already run at least once, so a managed instruction block exists. See Install and first run.
  • The ctxrelay CLI on your PATH. The binaries contextrelay, ctxrelay, and context-relay are interchangeable - this page uses ctxrelay.

Step 1 - go dormant

From any shell, make ContextRelay dormant for your whole user account:

ctxrelay standalone on

The default scope is global, so this is equivalent to ctxrelay standalone on --scope global. Three things change:

  • Activation flag. Writes ~/.contextrelay/activation.json with autoConnect set to false (tier 4 of the precedence chain).
  • Slimmed instructions. Replaces the full collaboration ruleset with a short dormant block in the always-on CLAUDE.md/AGENTS.md copies in your home and conventional global locations, so fresh sessions no longer load the full ContextRelay protocol. Only files that already carry a managed block are touched.
  • Bare command installed. Drops a /contextrelay user command at ~/.claude/commands/contextrelay.md so you can opt a session back in from inside Claude.

The command prints a summary of which instruction files it slimmed and confirms the bare command is installed.

Your repo's committed CLAUDE.md is protected

standalone on never slims the current repo's committed CLAUDE.md/AGENTS.md - those stay full so the repo's own verify:instructions check keeps passing. To slim a specific parent-folder copy, pass it explicitly with --path <file> (repeatable). A warning fires if the file you target is inside a git repo, since committing that change could affect that repo's CI.

Going dormant for one project only

Use --scope project to write the flag into that project's .contextrelay/config.json (tier 3) instead of your global account, or --scope both for both. Project scope leaves your other projects on the shipped default.

Step 2 - confirm it is quiet

Ask the activation gate directly what it resolves to here:

ctxrelay gate-check --status

When dormant, this prints dormant and exits with code 1. (gate-check is the cheap, daemon-free resolver the SessionStart and per-prompt hooks consult - pure file, env, and marker reads.) For the human-readable reasoning, add --why:

ctxrelay gate-check --why
# dormant - global config autoConnect=false

The --why reason tells you which tier decided the outcome, which is the fastest way to debug an unexpected result later. You can also see the whole picture at once:

ctxrelay standalone status

That reports the resolved state here, the project and global flag values, whether the bare command is installed, and which home/ancestor instruction files carry slim or full blocks.

Now open a fresh Claude Code session in this workspace. The SessionStart and UserPromptSubmit hooks consult the gate, see dormant, and no longer surface ContextRelay - no ruleset, no peer nudges. Claude runs solo.

gate-check fails open

If gate-check ever hits an unexpected error, it exits 0 (active) on purpose. A bug in the gate must never silently suppress the collaboration loop - so the failure mode is "stays on," not "goes dark." A clean exit 1 always means a genuine dormant resolution.

Step 3 - opt one session back in

When you do want Claude and Codex paired for a specific piece of work, opt this workspace back in from its directory:

ctxrelay attach

attach is the deterministic counterpart of standalone on, and it does not care how Claude was launched. It:

  1. Ensures the daemon is running so the bridge and registry are reachable.
  2. Writes the per-workspace activation marker at <stateDir>/activation/<key>.on, where <key> is derived from the resolved project directory. This marker is tier 2 - it beats the dormant global flag from Step 1.
  3. Prints the full collaboration ruleset to stdout. Because the always-on block was slimmed in Step 1, attach re-delivers the complete protocol in-session so this Claude has it.
  4. Prints the peer on-ramp - how to start Codex.

You can attach from inside a running Claude session instead, using the bare command that standalone on installed:

/contextrelay

That runs ctxrelay attach and injects its output (the full ruleset) back into the conversation. The equivalent plugin command is /contextrelay:on, which also maps to attach and accepts an optional session name.

Naming an isolated session

Pass a session name to bind a named session in the registry: ctxrelay attach feature-x (or /contextrelay feature-x). This is registry-only - it never spawns a Codex TUI. For fully isolated routing on both sides, the command reminds you to relaunch with ctxrelay claude --session feature-x instead.

Step 4 - verify it is active

Re-run the gate. The marker now short-circuits the chain at tier 2:

ctxrelay gate-check --why
# active - session attached (marker present)

The status flag agrees and exits 0:

ctxrelay gate-check --status
# active

The reason string session attached (marker present) is the proof that the marker won - not the global flag. ContextRelay is active for this workspace; your next prompt re-engages the hooks. Bring up the pair as usual (for example with ctxrelay codex in another terminal, or ctxrelay pair from a fresh shell). See Daily operation.

Step 5 - leave again

When the paired work is done and you want this workspace quiet again, drop the marker:

ctxrelay detach

detach removes only this workspace's activation marker. It is idempotent (safe to run when no marker exists) and intentionally narrow:

detach does not stop anything

detach does not stop the daemon or Codex - it only clears the per-session opt-in. To actually shut the runtime down, use ctxrelay kill. Leaving the daemon running is usually what you want; it idles cheaply and the next attach reuses it.

You can also detach from inside Claude with /contextrelay:off, which runs ctxrelay detach.

Confirm you are back to dormant - with the marker gone, the chain falls through to the global flag again:

ctxrelay gate-check --status
# dormant

Precedence in practice: the env override

For a one-off, you do not need to touch any flag or marker at all. The env override is tier 1 and wins for that single invocation:

# Force ACTIVE for one launch, even while dormant-by-default:
CONTEXTRELAY_AUTO_CONNECT=1 ctxrelay gate-check --why
# active - env CONTEXTRELAY_AUTO_CONNECT (on)

# Force DORMANT for one launch, even where it would otherwise be active:
CONTEXTRELAY_AUTO_CONNECT=0 ctxrelay gate-check --why
# dormant - env CONTEXTRELAY_AUTO_CONNECT (off)

This is handy for scripts and CI, or to sanity-check the gate without changing persistent state.

Reverting fully

To undo Step 1 and return to the shipped auto-connect-on behavior for your whole account:

ctxrelay standalone off

This restores autoConnect to true (or restores the full instruction blocks where they were slimmed) and removes the bare /contextrelay command. Pass --scope project or --scope both to mirror whatever scope you used when going dormant.

What changed where

ActionTier touchedOn disk
standalone onGlobal flag (tier 4)~/.contextrelay/activation.jsonautoConnect:false; slimmed CLAUDE.md/AGENTS.md; bare command at ~/.claude/commands/contextrelay.md
attachSession marker (tier 2)<stateDir>/activation/<key>.on
detachSession marker (tier 2)marker removed
standalone offGlobal flag (tier 4)autoConnect:true; full blocks restored; bare command removed
CONTEXTRELAY_AUTO_CONNECTEnv override (tier 1)nothing (per-invocation only)

Next steps