## 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
Add diff_has_code_files() and ci_required_for_pr() helpers to
ci-helpers.sh. Non-code PRs (docs/*, formulas/*, evidence/*, *.md)
that have no CI results now skip the CI gate instead of being stuck
forever.
Applied to:
- review-pr.sh: CI gate skipped for non-code PRs
- review-poll.sh: CI gate skipped for non-code PRs
- dev-poll.sh: CI state treated as "success" for non-code PRs in
orphan, stuck-PR, and backlog merge paths
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Widen the escalation dispatch pattern from `idle_timeout*` to also match
`idle_prompt*`. When an idle_prompt escalation arrives, the gardener now
creates an investigation sub-issue with a tailored description (session
returned to prompt without writing a phase signal) instead of silently
falling through to the recipe engine.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
- Remove CLAUDE_TIMEOUT no-op override — inherit factory default (7200s) from env.sh
- Use anchored grep -qxF "NO_PREDICTIONS" to avoid false early exits
- Fetch closed PRs (state=closed, merged_at filter) instead of open — captures merged activity signals
- Parse staleness age from filename date (YYYY-MM-DD.json) instead of file mtime
- Log a warning when date -d falls back due to non-GNU date
- Add comment explaining global lock serialisation trade-off
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After sending P0/P1 alerts immediately, reset the variables so they are
excluded from the final consolidated ALL_ALERTS send at the end of the
script.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Send P0 and P1 alerts to Matrix immediately after detection, before
per-project checks run. Also guard check_project calls with || flog so
any API timeout or jq parse failure inside the per-project scan cannot
kill the script before alert delivery.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- supervisor-poll.sh: check PR state before retrigger; discard stale escalations
for closed/merged PRs instead of pushing to their branches
- supervisor-poll.sh: bump escalation ts to now on failed retrigger push, so
the 30-min cooldown resets and alert flooding is avoided on persistent failures
- ci-helpers.sh: require at least one confirmed infra step before returning
"infra"; prevents false-positive when all step names are empty strings
- ci-helpers.sh: clarify header comment to distinguish per-function requirements
- AGENTS.md: document classify_pipeline_failure() in ci-helpers.sh table row
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Design principle for all disinto agents.
## Core idea
Split every agent into two layers:
- **Bash orchestrator (thin, deterministic):** session lifecycle, worktrees, locks, phase monitoring
- **Claude via formula (fat, judgment):** understand task, implement, handle reviews/CI/merge, adapt to novel situations
## Why
Agent scripts grow by accretion — every lesson becomes another if/else in bash. Formulas are refineable, learnable, and generalizable. Bash state machines are not.
## Includes
- Design principle with clear split criteria
- "When reviewing, ask these questions" checklist
- Current state assessment for all 5 agent types
- Risk mitigations (phase protocol as safety net)
Reviewers and planner should be aware of this principle when assessing PRs and planning work.
Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/disinto/pulls/240
Reviewed-by: Disinto_bot <disinto_bot@noreply.codeberg.org>
Prevent human comments appended to ISSUE_BODY from causing false
positive dependency blocks or spurious 'Existing PR:' recovery matches
in parse-deps.sh and the PR recovery guard.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Skip cleanup for sessions in needs_human/awaiting_ci/awaiting_review phases
- On tmux display-message failure skip session instead of defaulting to epoch 0
- Use paginated PR lookups (page loop checking page size, not match count)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fetches issue comments via Codeberg API and appends human comments
to the issue body in the Claude prompt. Bot comments (Disinto_bot,
disinto-factory) are filtered out.
One API call, zero new dependencies.
Captures design decisions from 2026-03-18 session with Johann.
## Key decisions
- **Evidence as integration layer**: formulas adapt external platforms (Analytics, Ponder, DigitalOcean) into structured JSON in `evidence/`; planner reads evidence, not platforms
- **Process types**: sense (holdout, user-test, measure-*) vs mutation (evolution, red-team)
- **Evidence-gated deployment**: no human "ship it" — all dimensions green = deploy
- **Resource allocation**: planner reads evidence staleness + current box load, decides what to run
- **Scope**: disinto is not a general company OS — it is finetuned for money → software → customer → knowledge → market fit
## New file
- `docs/EVIDENCE-ARCHITECTURE.md`
Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/disinto/pulls/207
Reviewed-by: Disinto_bot <disinto_bot@noreply.codeberg.org>
Add optional second TOKEN parameter to codeberg_api_all in lib/env.sh,
defaulting to $CODEBERG_TOKEN. Pass $REVIEW_BOT_TOKEN at the dismiss
block in review-pr.sh so reviews are fetched as the review bot account.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Look up the backlog label ID via the Gitea labels API (with fallback to
1300815) and replace '{"labels":["backlog"]}' with the integer ID form
at both call sites (cleanup() line 135 and idle_timeout handler line 713).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
phase-handler.sh does not source agent-session.sh directly — dev-agent.sh
sources agent-session.sh first, then sources phase-handler.sh. Correct
the Sourced-by entry to: dev-agent.sh, gardener-agent.sh.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Look up backlog label ID via Codeberg API at the start of the PHASE:failed
branch and replace '{"labels":["backlog"]}' at lines 547 and 628 with
the numeric ID, matching the pattern already used in gardener.
python3 is used directly by dev/dev-poll.sh (JSON CI-fix tracker),
lib/load-project.sh (TOML parsing via tomllib), and gardener/gardener-poll.sh
(recipe-matching engine). Add it to the dependency list and rephrase the
runtime constraint to reflect what is actually true.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
BusyBox grep (Alpine CI) does not treat \( as a literal paren in -E mode,
causing inject_formula to appear undefined even though it is defined in
lib/agent-session.sh. Using [(][)] is unambiguous in both GNU grep and
BusyBox grep.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>