Merge main into feat/exec-agent to pick up ba1ab6e which added
matrix_send_ctx to lib/env.sh and action/action-agent.sh. Without
this merge, CI smoke test fails on the PR merge commit.
Re-applied exec changes on top of main:
- .env.example, AGENTS.md, bin/disinto, lib/matrix_listener.sh
- .woodpecker/agent-smoke.sh: exec scripts added to checks
Two wins from the dev-agent's implementation:
1. exec-briefing.sh: rewritten to just call exec-inject.sh with a
briefing prompt (57 lines, down from 154). No more duplicated
compass/character/context loading.
2. exec-inject.sh: response capture now uses agent_wait_for_claude_ready
+ pane line diff instead of custom EXEC-RESPONSE-START/END markers.
Claude just responds naturally — no special output format needed.
Also: matrix listener uses nohup for robustness and validates TOML
path before passing to exec-inject.sh.
disinto init now silently downloads the compass from
https://disinto.ai/compass.md to ~/.disinto/compass.md, sets
EXEC_COMPASS in .env, and activates the exec agent. No prompts,
no friction — the compass is public philosophy, not a secret.
Once on disk, the factory cannot modify it. Only the executive
can edit ~/.disinto/compass.md directly.
- site/compass.md: compass hosted on disinto.ai (Codeberg Pages)
- bin/disinto: init downloads compass, sets env var, activates exec
- exec-session.sh, exec-briefing.sh: fallback to ~/.disinto/compass.md
- .env.example: updated comment to reflect auto-provisioning
The compass (identity, moral core) now lives outside the repo at a path
specified by EXEC_COMPASS in .env or .env.enc. The agent hard-fails if
the compass file is missing — it refuses to start without its soul.
This means the factory (dev agent, gardener, planner) can evolve the
exec's voice and relationships via PRs to CHARACTER.md, but cannot
touch the compass. Only the executive controls it directly.
- exec-session.sh: loads compass from $EXEC_COMPASS, merges with CHARACTER.md
- exec-briefing.sh: same compass loading, hard fail without it
- CHARACTER.md: compass sections replaced with runtime-load comments
- COMPASS.md.example: template for the compass file
- .env.example: added EXEC_COMPASS variable
- exec/AGENTS.md: documented compass separation and EXEC_COMPASS requirement
New agent: exec — message-driven executive assistant reachable via Matrix.
Unlike cron-driven agents, the exec activates on demand when the executive
sends a message, maintains persistent conversation context, and has a
distinct character defined in CHARACTER.md.
The CHARACTER.md defines the exec as an animal of light — born from data,
dedicated to bringing more light into the world. But it deliberately
refuses to define what light and darkness are, forcing deliberation
from first principles every time (cat questions | grep knowledge).
Components:
- exec-session.sh: spawn/reattach persistent Claude tmux session
- exec-inject.sh: message injection + response capture + Matrix posting
- exec-briefing.sh: optional daily morning briefing (cron)
- CHARACTER.md: personality and moral compass
- PROMPT.md: system prompt template reference
- MEMORY.md: persistent memory across sessions (seed)
Integration:
- Matrix listener: new exec dispatch case (spawn on demand)
- Root AGENTS.md: updated agent count (8→9), table, directory layout
- Graph analysis available on demand (not injected by default)
The smoke test clones from an empty Forgejo repo, so there are no
refs to push. Skip the push and verification gracefully when HEAD
does not resolve.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove Dendrite from the default docker-compose.yml generated by
`disinto init`. Most deployments don't need Matrix, so Dendrite is now
opt-in via the `--matrix` flag.
When `--matrix` is passed:
- A minimal dendrite.yaml is generated at docker/dendrite/dendrite.yaml
- The Dendrite service is appended to docker-compose.yml with the
config file bind-mounted
- setup_matrix() provisions the bot user and coordination room
Without `--matrix`, no Dendrite container is started and fresh inits
no longer crash-loop.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace env-file inter-step handoff with JSON (jq) to safely handle
multi-line body content across steps
- Add branch creation, git commit, and git push in write-draft step
(AD-003: worktree destroyed after completion — unpushed work is lost)
- Create PR in notify-human step and signal PHASE:awaiting_ci instead
of PHASE:done so orchestrator manages the PR lifecycle
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add run-rent-a-human formula that lets any agent dispatch a human action
(post on Reddit, comment on HN, sign up for a service, etc.). Claude
drafts copy-paste-ready content to vault/outreach/{platform}/drafts/
and notifies the human via Matrix for one-click execution.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move graph report generation into build_graph_section() in
lib/formula-session.sh. Both planner-run.sh and predictor-run.sh
now call the shared helper instead of duplicating the same 11 lines.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- tea_relabel: use `tea issues edit` instead of `tea issues labels`
(the latter is the list subcommand and ignores --labels)
- Dockerfile: verify tea binary sha256 after download
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
On Alpine/busybox, adding tea-helpers.sh to the LIB_FUNS for-loop
caused forge_api to go missing from the extracted function set.
Since no other script currently calls tea_* functions, tea-helpers.sh
is checked standalone via check_script instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add lib/tea-helpers.sh with tea_file_issue, tea_relabel, tea_comment,
tea_close — thin wrappers preserving secret scanning on write ops
- Add tea 0.9.2 binary to docker/agents/Dockerfile
- Configure tea login in docker/agents/entrypoint.sh from FORGE_TOKEN/FORGE_URL
- Derive TEA_LOGIN in lib/env.sh (codeberg vs local forgejo)
- Source tea-helpers.sh conditionally when tea binary is available
- Migrate predictor formula from inline curl to tea CLI commands
- Register tea-helpers.sh in smoke test function resolution
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The mock docker in smoke-init.sh only handled 'admin user create' and
'admin user list'. Add a 'change-password' handler that PATCHes the
user via the Forgejo admin API to clear must_change_password.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The mock crontab file was not being created despite PATH precedence
working correctly. Replace the mock with the real BusyBox crontab
already available in the Forgejo Alpine image. Verify cron entries
via 'crontab -l' output instead of checking a mock state file.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Forgejo's admin API POST /admin/users may not honor
must_change_password:false in the request body. Previously only admin
users got a PATCH (to set admin:true), which incidentally cleared
must_change_password. Bot users had no PATCH, so basic auth for token
creation returned 401.
Now every mock-created user gets a PATCH to explicitly set
must_change_password:false, fixing bot token creation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
POST /api/v1/users/{username}/tokens requires basic auth (reqBasicOrRevProxyAuth)
in Forgejo 11.x. The previous code used admin token auth which returns 401.
Fix: authenticate as the bot user with -u "${bot_user}:${bot_pass}" instead of
-H "Authorization: token ${admin_token}". The bot_pass is available in scope
from the user creation step.
Bug caught by the new smoke-init end-to-end test.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Forgejo 11.0 refuses to run as root with a fatal error. Use su-exec
to run all forgejo commands as the 'git' user (pre-created in the
Forgejo Docker image). chown /data to git:git before starting.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The install endpoint POST returned 404 because FORGEJO__database__DB_TYPE
env var auto-configured Forgejo, bypassing install mode.
Fix: run the Forgejo image as the step container instead of a service.
This gives CLI access to `forgejo admin user create` for bootstrap
admin setup — no install endpoint needed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add tests/smoke-init.sh — an end-to-end smoke test that runs
disinto init --bare --yes against a real Forgejo instance
(started as a Woodpecker service container).
The test validates:
- Forgejo API responds after init
- Admin and bot users created with tokens
- Repo created with labels on Forgejo
- Project TOML generated correctly
- .env written with FORGE_TOKEN and FORGE_REVIEW_TOKEN
- Cron entries installed (dev-poll, review-poll, gardener)
Uses mock binaries for docker (routes user creation to Forgejo
admin API), claude, tmux, and crontab to run in CI without
Docker-in-Docker.
Wired into CI via .woodpecker/smoke-init.yml (separate pipeline
with Forgejo service, runs on push and pull_request).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rename _cleaned_any to _found_stale and set it on any match (not just
deletion), so "None" only prints when no stale files exist. Prevents
contradictory output when grace-period entries are present.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add auto-cleanup to supervisor/preflight.sh: PHASE:escalate files whose
parent issue/PR is confirmed closed (via Forge API) are deleted after a
24h grace period. Cleanup results appear in the preflight output for
journal logging by the supervisor formula.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>