Remove all Matrix/Dendrite infrastructure:
- Delete lib/matrix_listener.sh (long-poll daemon), lib/matrix_listener.service
(systemd unit), lib/hooks/on-stop-matrix.sh (response streaming hook)
- Remove matrix_send() and matrix_send_ctx() from lib/env.sh
- Remove MATRIX_HOMESERVER auto-detection, MATRIX_THREAD_MAP from lib/env.sh
- Remove [matrix] section parsing from lib/load-project.sh
- Remove Matrix hook installation from lib/agent-session.sh
- Remove notify/notify_ctx helpers and Matrix thread tracking from
dev/dev-agent.sh and action/action-agent.sh
- Remove all matrix_send calls from dev-poll.sh, phase-handler.sh,
action-poll.sh, vault-poll.sh, vault-fire.sh, vault-reject.sh,
review-poll.sh, review-pr.sh, supervisor-poll.sh, formula-session.sh
- Remove Matrix listener startup from docker/agents/entrypoint.sh
- Remove append_dendrite_compose() and setup_matrix() from bin/disinto
- Remove --matrix flag from disinto init
- Clean Matrix references from .env.example, projects/*.toml.example,
formulas/*.toml, AGENTS.md, BOOTSTRAP.md, README.md, RESOURCES.md,
PHASE-PROTOCOL.md, and all agent AGENTS.md/PROMPT.md files
Status visibility now via Codeberg PR/issue activity. Human interaction
via vault items through forge. Proactive alerts via OpenClaw heartbeats.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Restructure session.lock from command-wrapper flock to fd-based flock so
the lock can be released when Claude is idle and re-acquired before
injecting the next prompt.
- agent-session.sh: add session_lock_acquire/release helpers, open fd in
create_agent_session instead of wrapping claude with flock, auto-acquire
in agent_inject_into_session before injecting
- phase-handler.sh: call session_lock_release at start of awaiting_ci and
awaiting_review handlers (Claude is idle during CI polling / review wait)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Non-blocking flock (-n) silently drops work items when concurrent agents
race for the lock. Switch to -w 300 so sessions queue up to 5 minutes,
and single-quote the lock path to handle spaces in $HOME.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Make ~/.claude volume mount read-write (was :ro) so containers can
write back refreshed OAuth tokens
- Wrap Claude CLI in flock(1) inside tmux sessions using
~/.claude/session.lock — prevents concurrent token refresh races
across agents sharing the same credentials
- Add ANTHROPIC_API_KEY detection in entrypoint.sh: when set, skips
OAuth entirely (no rotation issues, metered billing)
- Log active auth method (API key vs OAuth vs missing) at container
startup for easier 401 debugging
- Document 'claude auth login' requirement in disinto init output
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When Claude finishes a response but hasn't written to the PHASE file,
the stop hook now injects a nudge into the tmux session instead of just
marking idle. This gives Claude another chance to complete the phase
protocol before the monitor loop times out.
Key changes:
- on-idle-stop.sh: check phase file emptiness, nudge via tmux (max 2)
- agent-session.sh: pass phase_file + session to stop hook, clean up
nudge counter on session teardown
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Project-level .claude/settings.json overrides global ~/.claude/settings.json.
When agent-session.sh creates settings with hooks but without the skip flag,
Claude shows an interactive bypass-permissions confirmation dialog that blocks
all non-interactive tmux agent sessions.
Fixes#514.
- Add session name as third arg to guard hook (passed from agent-session.sh)
- Detect formula sessions (supervisor-*, gardener-*, planner-*, predictor-*)
- Guard 6: block filesystem access to factory root from worktrees, exempt formulas
- Guard 7: restrict system commands (kill, docker, tmux) to supervisor only
- Guard 2: allow formula agents rm -rf within factory root
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a phase change is detected (mtime changes), idle_elapsed was reset
but idle_pane_count was not. This meant idle counts accumulated before a
phase write carried into subsequent polls, so N consecutive idle polls
could be reached with fewer than N actual consecutive idle polls.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
TOML declares model = "opus". planner-poll.sh includes model: opus in
the issue YAML front matter. action-agent.sh extracts it and exports
CLAUDE_MODEL. create_agent_session passes --model to claude if set.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Guard against overwriting terminal phases (PHASE:done, PHASE:merged)
in on-stop-failure.sh to prevent false failures from same-turn race
- Declare sf_phase_marker explicitly in StopFailure block instead of
relying on phase_marker from PostToolUse block
- Add authentication_failed test (10c) and terminal phase guard tests
(10g, 10h)
- Fix fragile nested command substitution in test 10f fail() message
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary
- Claude Code v2.1.79 permanently shows `❯` in the input area even while actively thinking, causing `monitor_phase_loop` to false-positive on idle detection and kill working sessions after 90 seconds
- Replace `tmux capture-pane | grep ❯` with a Claude Code Stop hook (`lib/hooks/on-idle-stop.sh`) that writes a marker file only when Claude actually finishes responding
- Hook is installed per-worktree in `.claude/settings.json` by `create_agent_session`; marker cleaned up on inject/kill
## Test plan
- [x] Verified hook installs correctly in fresh worktree
- [x] Verified marker file appears only after Claude finishes responding (not during active thinking)
- [x] Verified live dev-agent session picks up fix and Claude works without being killed
- [x] Verified `agent_inject_into_session` clears marker before new work
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/disinto/pulls/272
Fixes#261
## Changes
Fixed gardener hanging forever when Claude skips phase protocol. Three changes: (1) gardener-agent.sh: replaced 999999s timeout with 7200s (2h, matching dev-agent); (2) lib/agent-session.sh: added idle-prompt detection to monitor_phase_loop — if Claude returns to the ❯ prompt for 3 consecutive polls with no phase file written, exits immediately with _MONITOR_LOOP_EXIT=idle_prompt (only fires when phase file is empty, so awaiting_ci/review waits are unaffected); (3) gardener prompt: removed 'no time limit' wording, replaced with explicit phase-write requirement.
Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/disinto/pulls/263
Reviewed-by: Disinto_bot <disinto_bot@noreply.codeberg.org>
Add optional 4th parameter to monitor_phase_loop for SESSION_NAME,
falling back to the $SESSION_NAME global for backwards-compatibility.
Document the full function signature in both the file header and inline comment.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Export LAST_PHASE_MTIME from monitor_phase_loop before invoking the callback
so that phase-handler.sh can compare phase file mtimes inside the awaiting_review
inner poll loop without hitting an unbound variable error under set -u.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Library functions need explicit session name argument — they no longer
have closure over $SESSION_NAME from the parent script.
- agent_kill_session: add $SESSION_NAME to all 11 call sites
- agent_inject_into_session: add $SESSION_NAME to all call sites in
phase-handler.sh and gardener-agent.sh
- agent_kill_session: guard against missing arg (defensive)
Both dev-agent.sh and gardener-agent.sh call these functions but they
were never implemented during the #158 extraction. Adds:
- create_agent_session(session, workdir) — tmux + claude + wait for ready
- inject_formula(session, text) — alias for agent_inject_into_session