Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/shell.yml
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,13 @@ jobs:
- name: Run tests/runtime-guard.sh
run: ./tests/runtime-guard.sh

posture:
name: installed-source posture (#314)
source-mode:
name: installed-source mode (#314, #324)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests/posture.sh
run: ./tests/posture.sh
- name: Run tests/source-mode.sh
run: ./tests/source-mode.sh

service-migration:
name: root -> non-root service identity migration (#93)
Expand Down
46 changes: 25 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,9 @@ operator-entrypoints/wp-coding-agents-setup/setup.md
| Flag | Description |
| --- | --- |
| `--runtime <name>` | Coding runtime: `opencode`, `claude-code`, or `codex`. Auto-detected when omitted. |
| `--posture <name>` | `engineering` (default) or `managed`. See [Install Posture](#install-posture). |
| `--managed-source <path>` | wp-content path the site owns and may edit under `--posture managed`. Repeatable. |
| `--managed-writable <path>` | Denied path to re-open for editing (e.g. `wp-config.php`). Not captured. Repeatable. |
| `--source-mode <name>` | `workspace` (default) or `owned`. See [Source Mode](#source-mode). `--posture` is a deprecated alias. |
| `--owned-source <path>` | wp-content path the site owns and may edit under `--source-mode owned`. Repeatable. |
| `--owned-writable <path>` | Denied path to re-open for editing (e.g. `wp-config.php`). Not captured. Repeatable. |
| `--log-path <path>` | Absolute path outside the site root the agent may read. Repeatable. |
| `--local` | Local machine mode. Skips server infrastructure. |
| `--existing` | Add to an existing WordPress install. |
Expand All @@ -185,14 +185,18 @@ operator-entrypoints/wp-coding-agents-setup/setup.md

Run `./setup.sh --help` for the complete setup surface.

## Install Posture
## Source Mode

Posture is the agent's relationship to the installed WordPress source. It is a
declared intent rather than a detected fact, and it is the single input that
decides the plugin set, every runtime permission surface, and the AGENTS.md
guidance the agent reads.
Source mode is where the agent's code changes land. It is a declared intent
rather than a detected fact, and it is the single input that decides the plugin
set, every runtime permission surface, and the AGENTS.md guidance the agent
reads.

| | `engineering` (default) | `managed` |
These are two shapes, not two levels. Neither is "more access" than the other —
`workspace` is in fact *stricter* on live source, since the installed tree is
read-only reference there. What it buys is git and review, not latitude.

| | `workspace` (default) | `owned` |
| --- | --- | --- |
| WordPress core (`wp-admin/`, `wp-includes/`, root bootstrap) | read-only | read-only |
| `wp-content/mu-plugins/`, `wp-config.php` | read-only | read-only, opt-in |
Expand All @@ -203,16 +207,16 @@ guidance the agent reads.
| How changes reach version control | the agent commits and opens pull requests | captured out-of-band by the operator |
| Runtimes | all | `opencode` only |

Both postures point the agent at the installed WordPress source as reference —
Both modes point the agent at the installed WordPress source as reference —
that is the section's purpose, and it is why a small model can be competent
about WordPress here without skills or fine-tuning. Reading is never
restricted. Everything below is about *writing*.

**Engineering** is the developer setup: the installed tree is reference
**Workspace** is the developer setup: the installed tree is reference
material, and every code change happens in a Data Machine Code workspace so it
is tracked in git and reviewed through GitHub.

**Managed** is for managed agentic hosting, where a non-technical owner should
**Owned** is for managed agentic hosting, where a non-technical owner should
never have to deal with pull requests. The agent edits the site's own theme and
plugins directly and its changes are live on save; something outside the box —
for example a scheduled `homeboy harvest` — captures them into git as restore
Expand All @@ -223,9 +227,9 @@ code, the stock themes, and the agent's own runtime, none of which the site
owns or the operator's capture records. Declare exactly what the site owns:

```bash
./setup.sh --posture managed \
--managed-source wp-content/themes/acme \
--managed-source wp-content/plugins/acme-core
./setup.sh --source-mode owned \
--owned-source wp-content/themes/acme \
--owned-source wp-content/plugins/acme-core
```

**The declared set must match what the operator's capture records** — a path
Expand All @@ -240,11 +244,11 @@ an agent able to edit them can rewrite its own instructions. They are denied by
default and re-opened only on request:

```bash
--managed-writable wp-config.php
--owned-writable wp-config.php
```

These are **editable but not captured**, and the generated guidance says so
explicitly. Conflating them with `--managed-source` would have AGENTS.md
explicitly. Conflating them with `--owned-source` would have AGENTS.md
promise that the work is recorded when it is not.

### Log access
Expand All @@ -260,19 +264,19 @@ writable):
```

A single source of truth (`lib/source-policy.sh`) derives the runtime
permissions and the generated guidance from the posture and these
permissions and the generated guidance from the source mode and these
declarations, so the prose cannot tell the agent to do something the
permissions then block.

Managed is currently supported on the `opencode` runtime only. OpenCode
evaluates permissions with `findLast` over rules in config key order, so a
narrow allow written after a broad deny wins. Claude Code treats deny as
absolute and Codex has no documented precedence for overlapping filesystem
entries, so both refuse managed posture rather than emit a permission set whose
entries, so both refuse owned mode rather than emit a permission set whose
behavior on a production site is unverified.

The chosen posture is recorded on the install, so `./upgrade.sh` converges to it
without repeating the flag. Pass `--posture` to either script to change it.
The chosen mode is recorded on the install, so `./upgrade.sh` converges to it
without repeating the flag. Pass `--source-mode` to either script to change it.

On VPS hosts with multiple Kimaki services, setup and upgrade select the unit
whose `WorkingDirectory=` exactly matches the WordPress site path. Ambiguous or
Expand Down
32 changes: 16 additions & 16 deletions guidance/_dispatch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,28 @@
# renders marker-delimited PHP blocks, and rewrites them idempotently. It used
# to also carry the CONTENT — the actual prose for every section — as heredocs
# inside sync functions. That coupling meant every new section, and every
# posture variant of an existing section, grew the same file. This directory is
# source-mode variant of an existing section, grew the same file. This directory is
# the content half; lib/agents-md-guidance.sh no longer knows what WordPress or
# Homeboy are.
#
# POSTURE VARIANTS
# SOURCE_MODE VARIANTS
#
# A section whose prose depends on the install posture (see lib/source-policy.sh)
# ships one file per posture:
# A section whose prose depends on the install source mode (see lib/source-policy.sh)
# ships one file per mode:
#
# guidance/wordpress-source.engineering.sh
# guidance/wordpress-source.managed.sh
#
# Resolution for section <id> is `<id>.<posture>.sh` when present, else
# `<id>.sh`. Posture-neutral sections ship a single `<id>.sh` and are unaffected.
# Resolution for section <id> is `<id>.<mode>.sh` when present, else
# `<id>.sh`. Mode-neutral sections ship a single `<id>.sh` and are unaffected.
# Two files that differ wholesale beat one file with a conditional wrapped
# around a heredoc: the diff of a posture is the file, and neither variant can
# around a heredoc: the diff of a mode is the file, and neither variant can
# quietly inherit a clause meant for the other.
#
# HOOK CONTRACT (functions namespaced guidance_* inside each unit file)
#
# Mandatory:
# guidance_id — SectionRegistry section id (stable across postures)
# guidance_id — SectionRegistry section id (stable across modes)
# guidance_priority — integer sort key within AGENTS.md
# guidance_label — human label recorded in section metadata
# guidance_render — emit the section markdown on stdout
Expand All @@ -60,8 +60,8 @@ fi
# guidance_names — every discoverable section id, one per line, de-duplicated.
#
# Discovery: any guidance/*.sh whose basename does not start with `_`. A
# `<id>.<posture>.sh` filename contributes the id once, no matter how many
# posture variants exist.
# `<id>.<mode>.sh` filename contributes the id once, no matter how many
# mode variants exist.
guidance_names() {
local f base id seen=""
for f in "$GUIDANCE_DIR"/*.sh; do
Expand All @@ -79,15 +79,15 @@ guidance_names() {
done
}

# guidance_file <id> — absolute path to the unit for the active posture.
# guidance_file <id> — absolute path to the unit for the active source mode.
#
# Prefers the posture-specific variant, falls back to the neutral file.
# Prefers the mode-specific variant, falls back to the neutral file.
guidance_file() {
local id="$1"
local posture="${POSTURE:-engineering}"
local mode="${SOURCE_MODE:-workspace}"

if [ -f "$GUIDANCE_DIR/${id}.${posture}.sh" ]; then
printf '%s' "$GUIDANCE_DIR/${id}.${posture}.sh"
if [ -f "$GUIDANCE_DIR/${id}.${mode}.sh" ]; then
printf '%s' "$GUIDANCE_DIR/${id}.${mode}.sh"
return 0
fi

Expand Down Expand Up @@ -178,7 +178,7 @@ guidance_call() {
)
}

# guidance_sync_all — sync every discovered section for the active posture.
# guidance_sync_all — sync every discovered section for the active source mode.
#
# Called once from setup.sh and once from upgrade.sh. Individual units may also
# be synced on their own (lib/homeboy.sh re-syncs the homeboy section after the
Expand Down
4 changes: 2 additions & 2 deletions guidance/abilities.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#!/bin/bash
# guidance/abilities.sh — WordPress Abilities discovery guidance.
#
# Posture-neutral: abilities are the tool surface in both engineering and
# managed installs, and the routing advice does not change with the agent's
# Mode-neutral: abilities are the tool surface in both workspace and
# owned-mode installs, and the routing advice does not change with the agent's
# relationship to installed source.

guidance_id() { printf 'abilities'; }
Expand Down
2 changes: 1 addition & 1 deletion guidance/homeboy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# guidance/homeboy.sh — Homeboy orchestration routing guidance (issues #208, #254, #298).
#
# Strictly presence-gated on the optional homeboy binary, and additionally on
# postures that actually have a workspace: the routing advice below is about
# modes that actually have a workspace: the routing advice below is about
# cooking tracked changes in managed worktrees, which is meaningless on a
# managed-hosting install where the agent edits live source and never touches
# git.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/bash
# guidance/wordpress-source.managed.sh — installed WordPress source, managed posture.
# guidance/wordpress-source.owned.sh — installed WordPress source, owned mode.
#
# WHAT THIS SECTION IS FOR
#
Expand Down Expand Up @@ -34,7 +34,7 @@ guidance_priority() { printf '1'; }
guidance_label() { printf 'WordPress Source'; }
guidance_description() { printf 'Points the agent at the installed WordPress source and names the trees this site owns.'; }
guidance_freshness() { printf 'conditional'; }
guidance_conditions() { printf 'Registered on managed-posture installations; the owned-source list is generated from the declared managed sources.'; }
guidance_conditions() { printf 'Registered on owned-mode installations; the owned-source list is generated from the declared owned sources.'; }

guidance_render() {
local owned writable
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/bash
# guidance/wordpress-source.engineering.sh — installed WordPress source, engineering posture.
# guidance/wordpress-source.workspace.sh — installed WordPress source, workspace mode.
#
# Same purpose as the managed variant: CAPABILITY. The agent should be an expert
# on its own runtime by reading the WordPress actually installed here rather
Expand All @@ -14,7 +14,7 @@ guidance_priority() { printf '1'; }
guidance_label() { printf 'WordPress Source'; }
guidance_description() { printf 'Points the agent at the installed WordPress source as read-only reference.'; }
guidance_freshness() { printf 'static'; }
guidance_conditions() { printf 'Registered by wp-coding-agents on engineering-posture installations.'; }
guidance_conditions() { printf 'Registered by wp-coding-agents on workspace-mode installations.'; }

guidance_render() {
cat <<'MD'
Expand Down
2 changes: 1 addition & 1 deletion lib/agents-md-guidance.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# has no opinion about what any section says. The prose lives in guidance/*.sh,
# one self-contained unit per section, discovered and dispatched by
# guidance/_dispatch.sh — see that file for the hook contract and for how
# posture selects between section variants.
# the source mode selects between section variants.
#
# Resolved file: $SITE_PATH/wp-content/mu-plugins/wp-coding-agents-agents-md.php
#
Expand Down
4 changes: 2 additions & 2 deletions lib/data-machine.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ install_data_machine() {
echo -e "${BLUE}[dry-run]${NC} $WP_CMD config set DATAMACHINE_WORKSPACE_PATH $DM_WORKSPACE_DIR --type=constant"
fi
else
log "Skipping Data Machine Code (posture: ${POSTURE:-managed} — no workspace on this install)"
log "Skipping Data Machine Code (source mode: ${SOURCE_MODE:-owned} — no workspace on this install)"
fi

set_compose_agents_md_constant
Expand Down Expand Up @@ -79,7 +79,7 @@ upgrade_data_machine_plugins() {
if source_policy_workspace_enabled; then
update_plugin_to_latest_tag data-machine-code https://github.com/Extra-Chill/data-machine-code.git
else
log " Skipping Data Machine Code (posture: ${POSTURE:-managed})"
log " Skipping Data Machine Code (source mode: ${SOURCE_MODE:-owned})"
fi

# Backfill the AGENTS.md composition gate on existing installs (idempotent).
Expand Down
Loading
Loading