Set coilyco ward workflow defaults in the aos KDL bundle #345

Closed
opened 2026-07-08 22:12:52 +00:00 by coilyco-ops · 3 comments
Member

Goal

Update the aos-authored ward KDL bundle so the coilyco deployment keeps direct-main as its fleet default while ward itself opts back into PR workflow.

This is the deployment-config slice for the ward workflow transition. It depends on ward supporting workflow policy in smart-defaults KDL (ward#707) and on PR workflow being able to complete the PR, CI, review, and merge lifecycle (ward#706).

Context

Aos is the source of truth for the coilyco ward spec bundle under .ward/, per docs/ward-specs.md. Ward consumes this bundle at release time. The requested shape is:

  • warded engineers use PRs by default in neutral ward.
  • coilyco's aos-authored KDL bundle changes that default to direct-main.
  • the ward repo locally overrides back to PRs so ward remains the PR test case.

Desired config

Once ward#707 lands a schema, update .ward/ward-kdl.defaults.kdl with the equivalent of:

smart-defaults {
    agent-workflow default="direct-main" {
        repo "coilyco-flight-deck/ward" workflow="pr"
    }
}

Keep the exact syntax aligned with the schema that lands in ward#707.

Acceptance

  • The aos bundle parses with ward's updated smart-default parser.
  • The coilyco fleet default resolves to direct-main.
  • coilyco-flight-deck/ward resolves to pr.
  • Relevant docs mention that aos intentionally overrides the neutral ward default for the coilyco deployment.
  • pre-commit run --all-files or the repo's ward exec validation passes.
## Goal Update the aos-authored ward KDL bundle so the coilyco deployment keeps direct-main as its fleet default while ward itself opts back into PR workflow. This is the deployment-config slice for the ward workflow transition. It depends on ward supporting workflow policy in `smart-defaults` KDL (ward#707) and on PR workflow being able to complete the PR, CI, review, and merge lifecycle (ward#706). ## Context Aos is the source of truth for the coilyco ward spec bundle under `.ward/`, per `docs/ward-specs.md`. Ward consumes this bundle at release time. The requested shape is: * warded engineers use PRs by default in neutral ward. * coilyco's aos-authored KDL bundle changes that default to direct-main. * the ward repo locally overrides back to PRs so ward remains the PR test case. ## Desired config Once ward#707 lands a schema, update `.ward/ward-kdl.defaults.kdl` with the equivalent of: ```kdl smart-defaults { agent-workflow default="direct-main" { repo "coilyco-flight-deck/ward" workflow="pr" } } ``` Keep the exact syntax aligned with the schema that lands in ward#707. ## Acceptance * The aos bundle parses with ward's updated smart-default parser. * The coilyco fleet default resolves to `direct-main`. * `coilyco-flight-deck/ward` resolves to `pr`. * Relevant docs mention that aos intentionally overrides the neutral ward default for the coilyco deployment. * `pre-commit run --all-files` or the repo's `ward exec` validation passes.
Author
Member

🔎 ward agent advisor

ward agent advisor --harness goose ran a one-shot standard research pass on this question:

Read the issue title, body, and comment thread below as the research brief. Identify the decisions, options, open questions, and risks, then give a clear advisory recommendation that can be posted back on the issue.

Additional framing from the dispatcher:
Design the aos KDL bundle update for this workflow-default override after ward#707 lands. Do not edit code. Post the exact files, validation commands, and dependency risks as an issue comment.


pre-commit installed at .git/hooks/pre-commit
pre-commit installed at .git/hooks/commit-msg
wrote /home/ubuntu/.mcporter/mcporter.json

__( O)>  ● new session · ollama qwen3-coder:30b

____) 20260708_1 · /workspace/agentic-os
L L goose is ready

────────────────────────────────────────
▸ list_resources extensionmanager

────────────────────────────────────────
▸ load_skill
name: tooling-warp

────────────────────────────────────────
▸ analyze
path: .ward

────────────────────────────────────────
▸ shell
command: find . -name "*.kdl" -type f | head -10

────────────────────────────────────────
▸ shell
command: ls -la .ward/

0 files, 0L, 0F, 0C (depth=3)
(8 files skipped: no parser)

./.ward/ward-kdl.forgejo.guardfile.kdl
./.ward/ward-kdl.signoz.guardfile.kdl
./.ward/ward-kdl.fleet.kdl
./.ward/ward-kdl.ollama.guardfile.kdltotal 328
dr-xr-xr-x 2 ubuntu ubuntu 4096 Jul 8 22:19 .
dr-xr-xr-x 19 ubuntu ubuntu 4096 Jul 8 22:19 ..
-r--r--r-- 1 ubuntu ubuntu 139714 Jul 8 22:19 forgejo.swagger.lock.json
-r--r--r-- 1 ubuntu ubuntu 118003 Jul 8 22:19 glitchtip.openapi.lock.json
-r--r--r-- 1 ubuntu ubuntu 16703 Jul 8 22:19 signoz.openapi.lock.json
-r--r--r-- 1 ubuntu ubuntu 1961 Jul 8 22:19 ward-kdl.fleet.kdl
-r--r--r-- 1 ubuntu ubuntu 15500 Jul 8 22:19 ward-kdl.forgejo.guardfile.kdl
-r--r--r-- 1 ubuntu ubuntu 1762 Jul 8 22:19 ward-kdl.ollama.guardfile.kdl
-r--r--r-- 1 ubuntu ubuntu 4863 Jul 8 22:19 ward-kdl.signoz.guardfile.kdl
-r--r--r-- 1 ubuntu ubuntu 11292 Jul 8 22:19 ward.yaml
────────────────────────────────────────
▸ shell
command: grep -r "smart-defaults" .ward/ || echo "No smart-defaults found"

No smart-defaults found
────────────────────────────────────────
▸ shell
command: cat .ward/ward-kdl.fleet.kdl

fleet {
schema-version 2

defaults {
    agent claude
    attribution name=coilyco-ops email=coilyco-ops@coilysiren.me
}

agent claude {
    binary claude
    context-level 2
    stream stream-json
    auth claude-keychain
    model claude-sonnet-4-6
    reasoning-effort medium
    argv {
        preflight claude -p
        headless claude -p --verbose --output-format stream-json
        interactive claude
    }
}

agent codex {
    binary codex
    context-level 1
    stream none
    auth codex-file
    model gpt-5.5
    reasoning-effort medium
    verbosity low
    argv {
        headless codex exec
        interactive codex
    }
}

agent opencode {
    binary opencode
    context-level 0
    stream none
    auth none
    model qwen3-coder:30b
    endpoint "http://localhost:11434/v1"
    argv {
        headless opencode run
        interactive opencode
    }
}

agent goose {
    binary goose
    context-level 1
    stream none
    auth ollama
    endpoint "http://localhost:11434/v1"
    argv {
        preflight goose run -t
        headless goose run -t
        interactive goose session
    }
}

roles {
    role director {
        // smarter agents than baseline
        agent claude {
            model claude-opus-4-8
            reasoning-effort high
        }
        agent codex {
            model gpt-5.5
            reasoning-effort high
        }
    }
    role advisor {
        // smarter agents than baseline
        agent claude {
            model claude-opus-4-8
            reasoning-effort high
        }
        agent codex {
            model gpt-5.5
            reasoning-effort high
        }
    }
}

}
────────────────────────────────────────
▸ shell
command: cat .ward/ward-kdl.defaults.kdl 2>/dev/null || echo "File does not exist"

File does not exist
────────────────────────────────────────
▸ search_available_extensions extensionmanager

────────────────────────────────────────
▸ shell
command: find /substrate -name "ward" -type d | head -10

/substrate/lore/.ward
/substrate/deploy/.ward
/substrate/ward
/substrate/ward/examples/toy/.ward
/substrate/ward/examples/ward-specs
/substrate/ward/.ward
/substrate/ward/.ward/ward-kdl
/substrate/ward/.ward/ward-kdl/ward-kdl-admin
/substrate/ward/.ward/ward-kdl/ward-kdl-read
/substrate/ward/.ward/ward-kdl/ward-kdl-write
────────────────────────────────────────
▸ shell
command: ls -la /substrate/ward/.ward/ward-kdl/

total 1332
drwxr-xr-x 5 root root 4096 Jul 8 22:19 .
drwxr-xr-x 3 root root 4096 Jul 8 22:19 ..
-rw-r--r-- 1 root root 119 Jul 8 22:19 README.md
-rw-r--r-- 1 root root 139714 Jul 8 22:19 forgejo.swagger.lock.json
-rw-r--r-- 1 root root 4632 Jul 8 22:19 glama.openapi.json
-rw-r--r-- 1 root root 6005 Jul 8 22:19 glama.openapi.lock.json
-rw-r--r-- 1 root root 247713 Jul 8 22:19 glitchtip.openapi.json
-rw-r--r-- 1 root root 118003 Jul 8 22:19 glitchtip.openapi.lock.json
-rw-r--r-- 1 root root 12853 Jul 8 22:19 signoz.openapi.json
-rw-r--r-- 1 root root 16703 Jul 8 22:19 signoz.openapi.lock.json
-rw-r--r-- 1 root root 2783 Jul 8 22:19 skillsmp.openapi.json
-rw-r--r-- 1 root root 2983 Jul 8 22:19 skillsmp.openapi.lock.json
-rw-r--r-- 1 root root 13189 Jul 8 22:19 specverb.lock
-rw-r--r-- 1 root root 60203 Jul 8 22:19 tailscale.openapi.lock.json
-rw-r--r-- 1 root root 225855 Jul 8 22:19 tailscale.openapi.yaml
-rw-r--r-- 1 root root 258619 Jul 8 22:19 trello.openapi.json
-rw-r--r-- 1 root root 71203 Jul 8 22:19 trello.openapi.lock.json
drwxr-xr-x 2 root root 4096 Jul 8 22:19 ward-kdl-admin
drwxr-xr-x 2 root root 4096 Jul 8 22:19 ward-kdl-read
drwxr-xr-x 2 root root 4096 Jul 8 22:19 ward-kdl-write
-rw-r--r-- 1 root root 942 Jul 8 22:19 ward-kdl.aider.guardfile.kdl
-rw-r--r-- 1 root root 1597 Jul 8 22:19 ward-kdl.aws.guardfile.kdl
-rw-r--r-- 1 root root 4097 Jul 8 22:19 ward-kdl.brew.guardfile.kdl
-rw-r--r-- 1 root root 1162 Jul 8 22:19 ward-kdl.claude.guardfile.kdl
-rw-r--r-- 1 root root 1145 Jul 8 22:19 ward-kdl.codex.guardfile.kdl
-rw-r--r-- 1 root root 464 Jul 8 22:19 ward-kdl.defaults.kdl
-rw-r--r-- 1 root root 3609 Jul 8 22:19 ward-kdl.docker.guardfile.kdl
-rw-r--r-- 1 root root 3533 Jul 8 22:19 ward-kdl.eco-observe.guardfile.kdl
-rw-r--r-- 1 root root 4609 Jul 8 22:19 ward-kdl.fleet.kdl
-rw-r--r-- 1 root root 2481 Jul 8 22:19 ward-kdl.forgejo-key.guardfile.kdl
-rw-r--r-- 1 root root 15500 Jul 8 22:19 ward-kdl.forgejo.guardfile.kdl
-rw-r--r-- 1 root root 3738 Jul 8 22:19 ward-kdl.git.guardfile.kdl
-rw-r--r-- 1 root root 2275 Jul 8 22:19 ward-kdl.glama.guardfile.kdl
-rw-r--r-- 1 root root 6025 Jul 8 22:19 ward-kdl.glitchtip.guardfile.kdl
-rw-r--r-- 1 root root 949 Jul 8 22:19 ward-kdl.goose.guardfile.kdl
-rw-r--r-- 1 root root 3223 Jul 8 22:19 ward-kdl.kubectl.guardfile.kdl
-rw-r--r-- 1 root root 1762 Jul 8 22:19 ward-kdl.ollama.guardfile.kdl
-rw-r--r-- 1 root root 1172 Jul 8 22:19 ward-kdl.opencode.guardfile.kdl
-rw-r--r-- 1 root root 4863 Jul 8 22:19 ward-kdl.signoz.guardfile.kdl
-rw-r--r-- 1 root root 1918 Jul 8 22:19 ward-kdl.skillsmp.guardfile.kdl
-rw-r--r-- 1 root root 1825 Jul 8 22:19 ward-kdl.tailscale.guardfile.kdl
-rw-r--r-- 1 root root 290 Jul 8 22:19 ward-kdl.topology.kdl
-rw-r--r-- 1 root root 1908 Jul 8 22:19 ward-kdl.trello.guardfile.kdl
────────────────────────────────────────
▸ shell
command: cat /substrate/ward/.ward/ward-kdl/ward-kdl.defaults.kdl

smart-defaults {
agent-reservation-ttl "1h"
agent-reservation-recheck-max "15s"
agent-reap-idle "1h"
agent-reap-max-cpu "5.0"
director-max-parallel "10"
director-limit "50"
director-poll-interval "30s"
reviewer-timeout "8m"
config-bundle-ttl "600"
container-assets-ttl "1h"
container-read-only-extra-repo-ttl "24h"
container-reap-keep "10"
// TODO: move advisor depth budgets and container-research setup budget.
}
────────────────────────────────────────
▸ shell
command: grep -r "agent-workflow" /substrate/ward/.ward/ward-kdl/ || echo "No agent-workflow found"

No agent-workflow found
────────────────────────────────────────
▸ shell
command: cat /substrate/ward/.ward/ward-kdl/ward-kdl.fleet.kdl

// Fleet config for ward (cli-guard fleetconfig, DIALECT 2). This is NOT a
// guardfile: it names which agents the ward fleet can run and how each one is
// launched (binary, context level, argv shape, model), never a permission. The
// .fleet.kdl suffix - no .guardfile. infix - keeps it out of the ward-kdl
// guardfile auto-discovery glob (ward-kdl..guardfile.kdl) and the exec/ops
// mirrors; it rides its own embed dir (cmd/ward/fleetassets/) and parser
// (cmd/ward/fleet.go via pkg/fleetconfig), legibly partitioned from the
// permission dialect (aos#310 §6, ward#415).
//
// This file is the single hand-edited source. make sync-fleet-assets copies
// it to cmd/ward/fleetassets/fleet.generated.kdl for go:embed (which cannot
// reach this sibling dir); fleetassets_test.go fails the build on drift.
//
// This is the single source of the roster + per-agent divergence, feeding the
// container_bootstrap.go env-defaults, restated in the ratified fleet grammar.
// ward#419 deleted the old agent-adapters.yaml mirror, collapsing the ward#415
// three-way pin to a two-way one: the contract test (agent_adapter_test.go,
// TestFleetSwitchesTwoWayPin) pins fleet.generated.kdl <-> the parseMode roster.
//
// POST-#412 roster: opencode is the canonical harness key (qwen is only the
// backing model + a deprecated --mode alias). The runtime reads this manifest
// (bootstrap defaults + the launcher-facing projection in agent_adapter.go).
fleet {
schema-version 2
// defaults mirror the container_bootstrap.go env-default constants: WARD_MODE
// -> defaults.agent, WARD_GIT_NAME/WARD_GIT_EMAIL -> defaults.attribution.
defaults {
agent claude
attribution name=coilyco-ops email=coilyco-ops@coilysiren.me
}
// claude: full context (2), stream-json headless, keychain auth. model /
// reasoning-effort are override-only (ward#616): empty defaults keep bare launch.
agent claude {
binary claude
context-level 2
stream stream-json
auth claude-keychain
model ""
reasoning-effort ""
argv {
preflight claude -p
headless claude -p --verbose --output-format stream-json
interactive claude
}
}
// codex: scoped context (level 1), no stream, codex-file auth, no pre-flight.
agent codex {
binary codex
context-level 1
stream none
auth codex-file
model gpt-5.4
reasoning-effort medium
verbosity low
argv {
headless codex exec
interactive codex
}
}
// opencode: minimal context (level 0), no stream, no host auth, no pre-flight.
agent opencode {
binary opencode
context-level 0
stream none
auth none
model qwen3-coder:30b
endpoint "http://localhost:11434/v1"
argv {
headless opencode run
interactive opencode
}
}
// goose: full context (level 2) like claude, no stream, ollama auth.
agent goose {
binary goose
context-level 2
stream none
auth ollama
argv {
preflight goose run -t
headless goose run -t
interactive goose session
}
}
// Per-role capability roster (ward#578) + per-agent model/effort overlay
// (cli-guard#192, ward#620); overlay precedence in docs/agent-config-overrides.md.
roles {
// engineer: no host reach; a cheaper model for parallel fan-out (ward#620).
role engineer {
agent claude {
model claude-fable-5
reasoning-effort medium
}
agent codex {
model gpt-5.4-mini
reasoning-effort medium
}
}
// director mirrors advisor's live-observe set (aws + tailnet, ward#547); its
// heartbeat wants the strongest model at 1M context (ward#620).
role director {
guardfiles ward-kdl.aws.guardfile.kdl ward-kdl.tailscale.guardfile.kdl
agent claude {
model "claude-opus-4-8[1m]"
reasoning-effort high
}
agent codex {
model gpt-5.5
reasoning-effort medium
}
}
// advisor does live-observe research: the aws SSM read + the tailnet route.
// advisor --no-tailnet opts a rare isolated run back out.
role advisor {
guardfiles ward-kdl.aws.guardfile.kdl ward-kdl.tailscale.guardfile.kdl
}
}
}
────────────────────────────────────────
▸ shell
command: find /substrate/ward -name "
.md" -exec grep -l "smart-defaults|workflow.*policy" {} ;

/substrate/ward/README.md
/substrate/ward/docs/troubleshooting.md
/substrate/ward/docs/agent-workflow.md
/substrate/ward/docs/agent-director-dispatch.md
/substrate/ward/docs/FEATURES.md
/substrate/ward/docs/agent-reservation.md
/substrate/ward/docs/config-source.md
/substrate/ward/docs/container-cleanup.md
/substrate/ward/docs/agent-reserved-immutable.md
/substrate/ward/docs/agent.md
────────────────────────────────────────
▸ shell
command: cat /substrate/ward/docs/agent-workflow.md


doc_goal: Let an operator pick the right per-run landing policy - direct-main, pr, or patch-only - by trust level and understand exactly what each mode changes in the seed, container env/label, and reaper gate, including the honest first-slice limits like the still-push-capable token.

ward agent: workflow modes

--workflow picks a dispatched engineer's landing policy - how the run is
allowed to turn finished work into a landed change (ward#508). One run, one
container, one issue; the workflow decides only how it lands, not what it
builds
.

warded engineer #98 --workflow direct-main   # (default) merge to main, push, close
warded engineer #98 --workflow pr            # branch + pull request; a human merges
warded engineer #98 --workflow patch-only    # produce a patch, land nothing

The default is direct-main, so an unflagged run behaves exactly as it always
has. The mode is visible in --print output, rides the container as the
WARD_WORKFLOW env var and a ward.workflow label, and is read by the reaper.

The three modes

  • direct-main (default) - the fast path: implement, commit, merge to
    main, push, and close the issue with a closes #N trailer. Intended for solo
    repos, trusted automation, and low-review surfaces. On GitHub (whose main
    is typically protected) direct-main already lands via a pull request - the
    forge decides, so the two collapse there.
  • pr - carry the work to a branch and a pull request instead of landing
    on main directly. The PR is the merge gate; a human or a follow-up loop lands
    it. The seed tells the agent to push the branch and open the PR, and not to
    push main.
  • patch-only - the run has no landing authority: it commits locally but
    produces a patch (git format-patch origin/main --stdout) and posts it in a
    comment for a human to review and apply. It neither pushes main nor opens a
    PR, and writes no closes #N trailer. Intended for untrusted targets,
    experiments, and high-risk work.

Which mode for which trust level

  • High trust (your own repo, an automation repo you own) - direct-main.
  • Shared / reviewed (a team repo where changes get looked at) - pr.
  • Low trust / exploratory (an external target, a risky change you want to eyeball
    before it touches the tree) - patch-only.

What the mode actually changes

  • Seed prompt / done-condition. The carry clause and the closing
    retrospective's "only after ..." landing phrase both shift with the mode, so a
    patch-only run is never told to merge to main, and a pr run is never told
    to push it. See agent.md for the seed shape.
  • Container env + label. A non-default run exports WARD_WORKFLOW=<mode> and
    wears a ward.workflow=<mode> label; direct-main omits both.
  • The reaper. ward container reap normally force-lands residual work on
    main at teardown. For a pr/patch-only run it reads WARD_WORKFLOW and
    refuses to push main, preserving any residual work on a ward-salvage/<id>
    branch instead. See container-reap.md.

Rough edges (first slice)

This first slice is deliberately minimal:

  • patch-only is enforced at the prompt + reaper layer, not the credential
    layer: the container still carries a push-capable token. Hard credential scoping
    (a read-only token) is the deferred "read-only credential hardening".
  • A pr/patch-only run's residual local commits are preserved on a salvage
    branch by the reaper (safe, but noisier than a dedicated "held" outcome).
  • The autonomous pre-flight still reads in merge-to-main
    terms; it judges feasibility, not the landing contract, so it is left as-is.

See also

  • agent.md - the ward agent verb family and the seed prompt.
  • container-reap.md - the teardown reaper the workflow gates.
  • agent-github.md - the GitHub lane, where direct-main already lands via a PR.
    ────────────────────────────────────────
    ▸ shell
    command: cat /substrate/ward/docs/config-source.md

doc_goal: Pin the WARD_CONFIG_REF config-source seam - the fs.FS the KDL build sites compile from, the unset-means-baked selection contract, the flat bundle layout, and the per-site degrade behavior.

The config source: WARD_CONFIG_REF and the fs.FS-at-launch seam

Since ward#653 (epic ward#650), ward's KDL surfaces compile at launch from a selected fs.FS, not a hard-wired embed. cmd/ward/configsource.go picks it. Four sites read it:

  • ward ops forgejo - spec guardfile + swagger lock, plus the optional admin guardfile.
  • the exec-dialect auto-mount - ward docker, ward agents <tool>, ward ops {aws,kubectl,...}.
  • the fleet roster - dialect-2 fleetconfig.Parse.
  • the smart-defaults bundle - runtime policy defaults in cmd/ward/smartdefaults.go.

Selection contract

  • Unset - the baked neutral default: the embedded mirrors of .ward/ward-kdl/ (drift-tested).
  • file://<dir> - os.DirFS(<dir>) over a local bundle directory in the
    flat layout below.
  • <host>/<owner>/<repo>[@<ref>]//<subpath> - the git-ref grammar, synced through the TTL-cached resolver (config-ref-resolver.md).

Bundle layout

A ref points at a flat bundle directory - the aos#332 layout, same as .ward/ward-kdl/:

  • ward-kdl.forgejo.guardfile.kdl + forgejo.swagger.lock.json - the spec
    surface for ops forgejo.
  • ward-kdl.<area>.guardfile.kdl (exec dialect) - auto-mounted at their wrap
    path (ward-kdl-in-ward.md); the exec scan mounts only
    files carrying an exec block.
  • ward-kdl.fleet.kdl - the dialect-2 fleet manifest.
  • ward-kdl.defaults.kdl - the launch-selected smart defaults for runtime policy knobs like reservation TTL, director cadence, and container retention.
  • ward-kdl.topology.kdl - container topology overlay. Env wins.
  • forgejo-admin.guardfile.kdl - optional; omitting it withholds
    ops forgejo admin/doctor.

Failure behavior

A set-but-unresolvable ref and a bundle that fails to parse both degrade per site, loudly:

  • ward ops forgejo mounts the error leaf - the failure surfaces on
    invocation (guardfile runtime failed to mount: ...), so a bad bundle can
    never silently drop a verb surface.
  • the exec auto-mount degrades with a stderr warning at launch.
  • fleet consumers (ward agents list, ward agent ...) error at verb time.
  • smart-defaults consumers (ward agent reap, ward agent director, ward agent review, reservation/comment code paths, container cleanup) error at
    verb time.
  • the rest of the CLI (version, exec, git, ...) keeps working.

There is no fallback from a named-but-broken source to the baked default.

See also

  • config-ref-resolver.md - the git-ref resolver.
  • ward-kdl.md - the build-time authoring layer the bundle comes from.
  • ward-kdl-in-ward.md - how exec guardfiles auto-mount.
  • config-discovery.md - the same loud-override rule for the allowlist.
    ────────────────────────────────────────
    ▸ shell
    command: ls -la /substrate/ward/docs/ | grep -E "(smart|default)"

(no output)

Command exited with code 1
────────────────────────────────────────
▸ shell
command: find /substrate/ward -name "*.md" -exec grep -l "smart-defaults|ward-kdl.defaults.kdl" {} ;

/substrate/ward/docs/troubleshooting.md
/substrate/ward/docs/ward-kdl.md
/substrate/ward/docs/agent-director-dispatch.md
/substrate/ward/docs/FEATURES.md
/substrate/ward/docs/agent-reservation.md
/substrate/ward/docs/config-source.md
/substrate/ward/docs/container-cleanup.md
/substrate/ward/docs/agent-reserved-immutable.md
────────────────────────────────────────
▸ shell
command: cat /substrate/ward/docs/ward-kdl.md | head -50


doc_goal: One answer to what ward-kdl is, how it differs from ward, and whether a repo needs a guardfile - build-time authoring layer vs run-time product.

ward-kdl: the build-time authoring layer

ward-kdl is the build-time authoring layer. ward is the run-time product that embeds what it authors. cli-guard is the engine both stand on. Three roles, told apart by when they run. The conceptual model lives in architecture.md.

Do you need to author a guardfile? (start here)

Almost certainly not. A repo needs a guardfile only when it runs its own ward ops operator surface. Dev-verb adoption is .ward/ward.yaml and nothing else.
The fork every adopter hits first:

  • Dev-verb gate (ward exec build/test/lint, ward git, the audit log) on your repo: a committed .ward/ward.yaml is the whole contract, no guardfile. That surface is forge-agnostic and already embedded in the installed ward. See ward-yaml.md.
  • Your own operator surface (ward ops forgejo/aws, the fleet roster) against your own endpoints, tokens, and owner gate: only then a guardfile, and even then you swap placeholders in the neutral example bundle and rebuild from source. See ward-kdl-authoring.md and the grammar in guardfile-grammar.md. Guardfiles are ward's own build-time internals, not a per-repo file a ward exec user maintains.

Build time: source in, validated artifact out

You author a source file, cli-guard compiles or validates it, ward embeds the
result. Nothing is fetched at runtime. ward-kdl is protoc for permissions and
fleet config, and you rarely run it by hand: you run what it produced and
regenerate when the source changes (make build-ward-kdl). Three dialects:

  • Dialect 1, permission surfaces - *.guardfile.kdl spec + exec files. Least-privilege, audited. Parsed by cli/execverb + http/specverb.
  • Dialect 2, fleet-config manifest - ward-kdl.fleet.kdl: identity, model, endpoint, attribution, roster defaults, sparse overrides, roles.
  • Dialect 3, operator-local - the same fleetconfig parser, sourced from a local ~/.ward/fleet.local.kdl, not embedded and tracked separately.
  • Smart defaults bundle - ward-kdl.defaults.kdl: launch-selected runtime policy defaults for reservation TTL, recheck cadence, reap thresholds, director cadence, and container retention. Parsed by ward at launch, embedded via defaultsassets/.

Run time: ward embeds the emitted surfaces

ward (public face warded) is the product a user installs. It embeds the ward-kdl surfaces as ward ops <api>, ward docker, ward agents <target>, then adds the run-time-only layers ward-kdl never produces: ward agent and ward exec. The embeds are the baked default: WARD_CONFIG_REF can select a live bundle at launch (config-source.md). Exec guardfiles auto-mount at their wrap path (ward-kdl-in-ward.md).

The per-area reference docs

Every guardfile gets a generated reference doc beside it, committed under docs/ward-kdl/. Emitted by ward-kdl's surface.Markdown(), they describe one area's verbs. ward-kdl-surface.md is the flat index across every area.

See also

Cross-reference convention from coilysiren/agentic-os#59.
────────────────────────────────────────
▸ shell
command: grep -A 20 -B 5 "agent-workflow" /substrate/ward/docs/troubleshooting.md

(no output)

Command exited with code 1
────────────────────────────────────────
▸ shell
command: grep -r "agent-workflow" /substrate/ward/docs/

/substrate/ward/docs/FEATURES.md:- --workflow direct-main|pr|patch-only (ward#508) - the dispatched engineer's landing policy: direct-main (default) merges to main and closes (unchanged); pr opens a branch + pull request; patch-only posts a patch with no landing authority. The mode shifts the seed, rides the container env + a ward.workflow label, and gates the reaper's main push. See agent-workflow.md.
/substrate/ward/docs/agent.md:- agent-workflow.md - --workflow direct-main|pr|patch-only, the run's landing policy.
────────────────────────────────────────
▸ todo_write todo
content: - [x] Analyze current KDL structures in agentic-os and ward repos

  • Identify existing workflow configuration patterns

  • Research smart-defaults schema from ward#707 (not yet implemented)

  • Determine where to add the agent-workflow configuration

  • Review issue requirements for the coilyco override

  • Gather context on PR workflow dependencies: ward#706 and ward#707

    ────────────────────────────────────────
    ▸ shell
    command: curl -s "https://forgejo.coilysiren.me/api/v1/repos/coilyco-flight-deck/ward/issues/707" | grep -E ""title":"|"body":""

{"id":4200,"url":"https://forgejo.coilysiren.me/api/v1/repos/coilyco-flight-deck/ward/issues/707","html_url":"coilyco-flight-deck/ward#707","number":707,"user":{"id":7,"login":"coilyco-ops","login_name":"","source_id":0,"full_name":"Coilyco Robotic Operations Division","email":"coilyco-ops@noreply.forgejo.coilysiren.me","avatar_url":"https://forgejo.coilysiren.me/avatars/ed264a3b7b6770327da211496912cfff5bacae8ac8fa8a9748e3d5ea638b875e","html_url":"https://forgejo.coilysiren.me/coilyco-ops","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2026-06-18T03:44:21Z","restricted":false,"active":false,"prohibit_login":false,"location":"","pronouns":"ro / bot","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"coilyco-ops"},"original_author":"","original_author_id":0,"title":"Make agent workflow defaults configurable and default engineers to PRs","body":"## Goal\n\nMake ward's agent workflow selection config-driven, flip warded engineers to PR workflow by default, and support per-repo workflow overrides.\n\nThis is the configuration half of the direct-main to PR transition. It should land after or alongside the PR lifecycle work in ward#706, because defaulting to pr should mean the run can actually create the PR, wait for CI, and merge with a merge commit.\n\n## Current behavior\n\n* cmd/ward/agent_workflow.go has defaultWorkflow = workflowDirectMain.\n* workflowFlag() exposes --workflow with a hard-coded direct-main default.\n* agentWorkflow() only parses the CLI flag.\n* container_compute.go omits WARD_WORKFLOW and the ward.workflow label for default/direct-main runs.\n* docs/agent-workflow.md documents direct-main as the default.\n* Runtime policy KDL currently lives in ward-kdl.defaults.kdl under smart-defaults, but it has no workflow policy nodes.\n\n## Desired behavior\n\n* The built-in ward default becomes pr.\n* smart-defaults KDL can set the default workflow.\n* smart-defaults KDL can override workflow by repo, keyed by owner/repo.\n* CLI --workflow still wins over config.\n* Repo override wins over fleet/default workflow.\n* Invalid configured workflow values fail closed with a useful error.\n* Dry-run/print output, reservation records, container env/labels, seed prompts, docs, and tests all show the resolved workflow.\n* Existing explicit --workflow direct-main and --workflow patch-only behavior keeps working.\n\n## Sketch\n\nOne plausible KDL shape:\n\nkdl\nsmart-defaults {\n agent-workflow default=\"pr\" {\n repo \"coilyco-flight-deck/agentic-os\" workflow=\"direct-main\"\n repo \"coilyco-flight-deck/ward\" workflow=\"pr\"\n }\n}\n\n\nUse the repo key that is already resolved by dispatch (agentIssueRef.repoSlug()), not cwd discovery, so bare refs and full refs behave the same.\n\n## Acceptance\n\n* Unit tests cover built-in default, KDL default, repo override, CLI precedence, invalid values, and env/label projection.\n* docs/agent-workflow.md is updated to describe PR as the default and config override precedence.\n* docs/FEATURES.md is updated if this changes the feature inventory.","ref":"","assets":[],"labels":[],"milestone":null,"assignee":null,"assignees":null,"state":"open","is_locked":false,"comments":1,"created_at":"2026-07-08T22:12:40Z","updated_at":"2026-07-08T22:19:00Z","closed_at":null,"due_date":null,"pull_request":null,"repository":{"id":4,"name":"ward","owner":"coilyco-flight-deck","full_name":"coilyco-flight-deck/ward"},"pin_order":0}
────────────────────────────────────────
▸ shell
command: curl -s "https://forgejo.coilysiren.me/api/v1/repos/coilyco-flight-deck/ward/issues/706" | grep -E ""title":"|"body":""

{"id":4199,"url":"https://forgejo.coilysiren.me/api/v1/repos/coilyco-flight-deck/ward/issues/706","html_url":"coilyco-flight-deck/ward#706","number":706,"user":{"id":7,"login":"coilyco-ops","login_name":"","source_id":0,"full_name":"Coilyco Robotic Operations Division","email":"coilyco-ops@noreply.forgejo.coilysiren.me","avatar_url":"https://forgejo.coilysiren.me/avatars/ed264a3b7b6770327da211496912cfff5bacae8ac8fa8a9748e3d5ea638b875e","html_url":"https://forgejo.coilysiren.me/coilyco-ops","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2026-06-18T03:44:21Z","restricted":false,"active":false,"prohibit_login":false,"location":"","pronouns":"ro / bot","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"coilyco-ops"},"original_author":"","original_author_id":0,"title":"Make PR workflow create, wait, and merge pull requests","body":"## Goal\n\nChange --workflow pr from a branch-and-human-gate prompt into a complete ward landing workflow for Forgejo engineers.\n\nToday PR workflow only tells the container agent to push a branch and open a pull request, then it stops. The requested default change needs PR mode to be a real autonomous path first: create the PR, wait for Forgejo Actions or required status checks to finish, run the existing review gate after CI is green, then merge the PR with a merge commit.\n\n## Context read before filing\n\n* cmd/ward/agent_workflow.go currently documents pr as branch + PR with a human or follow-up loop landing it.\n* docs/agent-workflow.md says the same and names this as a first-slice limitation.\n* docs/ward-kdl/ward-kdl.forgejo.write.guardfile.md currently denies PR view/list and says PRs are read through the web UI.\n* The Forgejo swagger lock already contains pull request, action task, branch protection, and merge related shapes, so this is a product/guarded-surface gap rather than an API absence.\n\n## Desired behavior\n\n* Forgejo pr workflow opens a real pull request against main from the feature branch.\n* Ward waits for CI/status checks for that PR branch/head before review and merge.\n* Ward runs the existing in-container review gate only after CI is green.\n* Ward merges with a merge commit, not squash, rebase, or fast-forward.\n* The issue close path is preserved through the PR body or merge commit message using closes #N.\n* Failure to create the PR, green CI, pass review, or merge is reported as blocked/failed with useful context on the issue.\n* GitHub behavior stays compatible with the existing GitHub PR lane.\n\n## Notes\n\nThis should not rely on the agent improvising hidden curl calls. Prefer a ward-owned helper or guarded Forgejo verbs with tests around request shape, polling behavior, and failure classification.","ref":"","assets":[],"labels":[],"milestone":null,"assignee":null,"assignees":null,"state":"open","is_locked":false,"comments":1,"created_at":"2026-07-08T22:12:26Z","updated_at":"2026-07-08T22:13:05Z","closed_at":null,"due_date":null,"pull_request":null,"repository":{"id":4,"name":"ward","owner":"coilyco-flight-deck","full_name":"coilyco-flight-deck/ward"},"pin_order":0}{"summary":"## Summary\n\nThis issue is about updating the aos-authored ward KDL bundle to override the default workflow for the coilyco deployment while keeping ward itself configured to use PR workflow by default. Based on the context and the referenced issues (ward#706 and ward#707), I've analyzed the configuration structure required.\n\n## Analysis\n\nFrom my research, I identified that:\n\n1. Current State: The ward-kdl.defaults.kdl file in ward repo currently contains only basic smart-defaults configuration but lacks workflow configuration capabilities\n2. Required Changes: Once ward#707 (smart-defaults schema for workflow) lands, the agentic-os KDL bundle needs to be updated to set agent-workflow default as "direct-main" while specifically overriding the coilyco-flight-deck/ward repo to use "pr"\n3. Configuration Location: The aos bundle should modify .ward/ward-kdl.defaults.kdl (or equivalent) to add the workflow configuration\n4. Schema: Based on the ward#707 issue description, the expected KDL shape is:\nkdl\nsmart-defaults {\n agent-workflow default=\"direct-main\" {\n repo \"coilyco-flight-deck/ward\" workflow=\"pr\"\n }\n}\n\n\n## Risk Assessment\n\n- Dependency Risk: This change is dependent on ward#707 landing first to implement the smart-defaults schema for agent-workflow configuration. Without this, the configuration will not parse correctly.\n- Compatibility Risk: The PR workflow lifecycle (ward#706) must be fully implemented so that coilyco-flight-deck/ward can successfully go through full PR creation, CI wait, review, and merge lifecycle.\n- Timing Risk: If agentic-os makes changes before ward#707 is implemented, the KDL will fail to parse during ward's startup.\n\n## Recommendation\n\nThis should be implemented AFTER ward#707 lands with implementation of the smart-defaults schema for agent workflow. The change should be limited to modifying the .ward/ward-kdl.defaults.kdl file inside the agentic-os repository, with validation that it parses correctly using pre-commit run --all-files or ward exec as specified in the issue acceptance criteria.", "issues": [{"repo": "coilyco-flight-deck/ward", "title": "Make agent workflow defaults configurable and default engineers to PRs", "body": "## Goal\n\nMake ward's agent workflow selection config-driven, flip warded engineers to PR workflow by default, and support per-repo workflow overrides.\n\nThis is the configuration half of the direct-main to PR transition. It should land after or alongside the PR lifecycle work in ward#706, because defaulting to pr should mean the run can actually create the PR, wait for CI, and merge with a merge commit.\n\n## Current behavior\n\n* cmd/ward/agent_workflow.go has defaultWorkflow = workflowDirectMain.\n* workflowFlag() exposes --workflow with a hard-coded direct-main default.\n* agentWorkflow() only parses the CLI flag.\n* container_compute.go omits WARD_WORKFLOW and the ward.workflow label for default/direct-main runs.\n* docs/agent-workflow.md documents direct-main as the default.\n* Runtime policy KDL currently lives in ward-kdl.defaults.kdl under smart-defaults, but it has no workflow policy nodes.\n\n## Desired behavior\n\n* The built-in ward default becomes pr.\n* smart-defaults KDL can set the default workflow.\n* smart-defaults KDL can override workflow by repo, keyed by owner/repo.\n* CLI --workflow still wins over config.\n* Repo override wins over fleet/default workflow.\n* Invalid configured workflow values fail closed with a useful error.\n* Dry-run/print output, reservation records, container env/labels, seed prompts, docs, and tests all show the resolved workflow.\n* Existing explicit --workflow direct-main and --workflow patch-only behavior keeps working.\n\n## Sketch\n\nOne plausible KDL shape:\n\nkdl\nsmart-defaults {\n agent-workflow default=\"pr\" {\n repo \"coilyco-flight-deck/agentic-os\" workflow=\"direct-main\"\n repo \"coilyco-flight-deck/ward\" workflow=\"pr\"\n }\n}\n\n\nUse the repo key that is already resolved by dispatch (agentIssueRef.repoSlug()), not cwd discovery, so bare refs and full refs behave the same.\n\n## Acceptance\n\n* Unit tests cover built-in default, KDL default, repo override, CLI precedence, invalid values, and env/label projection.\n* docs/agent-workflow.md is updated to describe PR as the default and config override precedence.\n* docs/FEATURES.md is updated if this changes the feature inventory."}, {"repo": "coilyco-flight-deck/ward", "title": "Make PR workflow create, wait, and merge pull requests", "body": "## Goal\n\nChange --workflow pr from a branch-and-human-gate prompt into a complete ward landing workflow for Forgejo engineers.\n\nToday PR workflow only tells the container agent to push a branch and open a pull request, then it stops. The requested default change needs PR mode to be a real autonomous path first: create the PR, wait for Forgejo Actions or required status checks to finish, run the existing review gate after CI is green, then merge the PR with a merge commit.\n\n## Context read before filing\n\n* cmd/ward/agent_workflow.go currently documents pr as branch + PR with a human or follow-up loop landing it.\n* docs/agent-workflow.md says the same and names this as a first-slice limitation.\n* docs/ward-kdl/ward-kdl.forgejo.write.guardfile.md currently denies PR view/list and says PRs are read through the web UI.\n* The Forgejo swagger lock already contains pull request, action task, branch protection, and merge related shapes, so this is a product/guarded-surface gap rather than an API absence.\n\n## Desired behavior\n\n* Forgejo pr workflow opens a real pull request against main from the feature branch.\n* Ward waits for CI/status checks for that PR branch/head before review and merge.\n* Ward runs the existing in-container review gate only after CI is green.\n* Ward merges with a merge commit, not squash, rebase, or fast-forward.\n* The issue close path is preserved through the PR body or merge commit message using closes #N.\n* Failure to create the PR, green CI, pass review, or merge is reported as blocked/failed with useful context on the issue.\n* GitHub behavior stays compatible with the existing GitHub PR lane.\n\n## Notes\n\nThis should not rely on the agent improvising hidden curl calls. Prefer a ward-owned helper or guarded Forgejo verbs with tests around request shape, polling behavior, and failure classification."}]


Researched and posted automatically by ward agent advisor --harness goose (ward#179). This is one-shot research, not a carried change - verify before acting on it.

— Goose, via ward agent

### 🔎 ward agent advisor `ward agent advisor --harness goose` ran a one-shot **standard** research pass on this question: > Read the issue title, body, and comment thread below as the research brief. Identify the decisions, options, open questions, and risks, then give a clear advisory recommendation that can be posted back on the issue. > > Additional framing from the dispatcher: > Design the aos KDL bundle update for this workflow-default override after ward#707 lands. Do not edit code. Post the exact files, validation commands, and dependency risks as an issue comment. --- pre-commit installed at .git/hooks/pre-commit pre-commit installed at .git/hooks/commit-msg wrote /home/ubuntu/.mcporter/mcporter.json __( O)> ● new session · ollama qwen3-coder:30b \____) 20260708_1 · /workspace/agentic-os L L goose is ready ──────────────────────────────────────── ▸ list_resources extensionmanager ──────────────────────────────────────── ▸ load_skill name: tooling-warp ──────────────────────────────────────── ▸ analyze path: .ward ──────────────────────────────────────── ▸ shell command: find . -name "*.kdl" -type f | head -10 ──────────────────────────────────────── ▸ shell command: ls -la .ward/ 0 files, 0L, 0F, 0C (depth=3) (8 files skipped: no parser) ./.ward/ward-kdl.forgejo.guardfile.kdl ./.ward/ward-kdl.signoz.guardfile.kdl ./.ward/ward-kdl.fleet.kdl ./.ward/ward-kdl.ollama.guardfile.kdltotal 328 dr-xr-xr-x 2 ubuntu ubuntu 4096 Jul 8 22:19 . dr-xr-xr-x 19 ubuntu ubuntu 4096 Jul 8 22:19 .. -r--r--r-- 1 ubuntu ubuntu 139714 Jul 8 22:19 forgejo.swagger.lock.json -r--r--r-- 1 ubuntu ubuntu 118003 Jul 8 22:19 glitchtip.openapi.lock.json -r--r--r-- 1 ubuntu ubuntu 16703 Jul 8 22:19 signoz.openapi.lock.json -r--r--r-- 1 ubuntu ubuntu 1961 Jul 8 22:19 ward-kdl.fleet.kdl -r--r--r-- 1 ubuntu ubuntu 15500 Jul 8 22:19 ward-kdl.forgejo.guardfile.kdl -r--r--r-- 1 ubuntu ubuntu 1762 Jul 8 22:19 ward-kdl.ollama.guardfile.kdl -r--r--r-- 1 ubuntu ubuntu 4863 Jul 8 22:19 ward-kdl.signoz.guardfile.kdl -r--r--r-- 1 ubuntu ubuntu 11292 Jul 8 22:19 ward.yaml ──────────────────────────────────────── ▸ shell command: grep -r "smart-defaults" .ward/ || echo "No smart-defaults found" No smart-defaults found ──────────────────────────────────────── ▸ shell command: cat .ward/ward-kdl.fleet.kdl fleet { schema-version 2 defaults { agent claude attribution name=coilyco-ops email=coilyco-ops@coilysiren.me } agent claude { binary claude context-level 2 stream stream-json auth claude-keychain model claude-sonnet-4-6 reasoning-effort medium argv { preflight claude -p headless claude -p --verbose --output-format stream-json interactive claude } } agent codex { binary codex context-level 1 stream none auth codex-file model gpt-5.5 reasoning-effort medium verbosity low argv { headless codex exec interactive codex } } agent opencode { binary opencode context-level 0 stream none auth none model qwen3-coder:30b endpoint "http://localhost:11434/v1" argv { headless opencode run interactive opencode } } agent goose { binary goose context-level 1 stream none auth ollama endpoint "http://localhost:11434/v1" argv { preflight goose run -t headless goose run -t interactive goose session } } roles { role director { // smarter agents than baseline agent claude { model claude-opus-4-8 reasoning-effort high } agent codex { model gpt-5.5 reasoning-effort high } } role advisor { // smarter agents than baseline agent claude { model claude-opus-4-8 reasoning-effort high } agent codex { model gpt-5.5 reasoning-effort high } } } } ──────────────────────────────────────── ▸ shell command: cat .ward/ward-kdl.defaults.kdl 2>/dev/null || echo "File does not exist" File does not exist ──────────────────────────────────────── ▸ search_available_extensions extensionmanager ──────────────────────────────────────── ▸ shell command: find /substrate -name "*ward*" -type d | head -10 /substrate/lore/.ward /substrate/deploy/.ward /substrate/ward /substrate/ward/examples/toy/.ward /substrate/ward/examples/ward-specs /substrate/ward/.ward /substrate/ward/.ward/ward-kdl /substrate/ward/.ward/ward-kdl/ward-kdl-admin /substrate/ward/.ward/ward-kdl/ward-kdl-read /substrate/ward/.ward/ward-kdl/ward-kdl-write ──────────────────────────────────────── ▸ shell command: ls -la /substrate/ward/.ward/ward-kdl/ total 1332 drwxr-xr-x 5 root root 4096 Jul 8 22:19 . drwxr-xr-x 3 root root 4096 Jul 8 22:19 .. -rw-r--r-- 1 root root 119 Jul 8 22:19 README.md -rw-r--r-- 1 root root 139714 Jul 8 22:19 forgejo.swagger.lock.json -rw-r--r-- 1 root root 4632 Jul 8 22:19 glama.openapi.json -rw-r--r-- 1 root root 6005 Jul 8 22:19 glama.openapi.lock.json -rw-r--r-- 1 root root 247713 Jul 8 22:19 glitchtip.openapi.json -rw-r--r-- 1 root root 118003 Jul 8 22:19 glitchtip.openapi.lock.json -rw-r--r-- 1 root root 12853 Jul 8 22:19 signoz.openapi.json -rw-r--r-- 1 root root 16703 Jul 8 22:19 signoz.openapi.lock.json -rw-r--r-- 1 root root 2783 Jul 8 22:19 skillsmp.openapi.json -rw-r--r-- 1 root root 2983 Jul 8 22:19 skillsmp.openapi.lock.json -rw-r--r-- 1 root root 13189 Jul 8 22:19 specverb.lock -rw-r--r-- 1 root root 60203 Jul 8 22:19 tailscale.openapi.lock.json -rw-r--r-- 1 root root 225855 Jul 8 22:19 tailscale.openapi.yaml -rw-r--r-- 1 root root 258619 Jul 8 22:19 trello.openapi.json -rw-r--r-- 1 root root 71203 Jul 8 22:19 trello.openapi.lock.json drwxr-xr-x 2 root root 4096 Jul 8 22:19 ward-kdl-admin drwxr-xr-x 2 root root 4096 Jul 8 22:19 ward-kdl-read drwxr-xr-x 2 root root 4096 Jul 8 22:19 ward-kdl-write -rw-r--r-- 1 root root 942 Jul 8 22:19 ward-kdl.aider.guardfile.kdl -rw-r--r-- 1 root root 1597 Jul 8 22:19 ward-kdl.aws.guardfile.kdl -rw-r--r-- 1 root root 4097 Jul 8 22:19 ward-kdl.brew.guardfile.kdl -rw-r--r-- 1 root root 1162 Jul 8 22:19 ward-kdl.claude.guardfile.kdl -rw-r--r-- 1 root root 1145 Jul 8 22:19 ward-kdl.codex.guardfile.kdl -rw-r--r-- 1 root root 464 Jul 8 22:19 ward-kdl.defaults.kdl -rw-r--r-- 1 root root 3609 Jul 8 22:19 ward-kdl.docker.guardfile.kdl -rw-r--r-- 1 root root 3533 Jul 8 22:19 ward-kdl.eco-observe.guardfile.kdl -rw-r--r-- 1 root root 4609 Jul 8 22:19 ward-kdl.fleet.kdl -rw-r--r-- 1 root root 2481 Jul 8 22:19 ward-kdl.forgejo-key.guardfile.kdl -rw-r--r-- 1 root root 15500 Jul 8 22:19 ward-kdl.forgejo.guardfile.kdl -rw-r--r-- 1 root root 3738 Jul 8 22:19 ward-kdl.git.guardfile.kdl -rw-r--r-- 1 root root 2275 Jul 8 22:19 ward-kdl.glama.guardfile.kdl -rw-r--r-- 1 root root 6025 Jul 8 22:19 ward-kdl.glitchtip.guardfile.kdl -rw-r--r-- 1 root root 949 Jul 8 22:19 ward-kdl.goose.guardfile.kdl -rw-r--r-- 1 root root 3223 Jul 8 22:19 ward-kdl.kubectl.guardfile.kdl -rw-r--r-- 1 root root 1762 Jul 8 22:19 ward-kdl.ollama.guardfile.kdl -rw-r--r-- 1 root root 1172 Jul 8 22:19 ward-kdl.opencode.guardfile.kdl -rw-r--r-- 1 root root 4863 Jul 8 22:19 ward-kdl.signoz.guardfile.kdl -rw-r--r-- 1 root root 1918 Jul 8 22:19 ward-kdl.skillsmp.guardfile.kdl -rw-r--r-- 1 root root 1825 Jul 8 22:19 ward-kdl.tailscale.guardfile.kdl -rw-r--r-- 1 root root 290 Jul 8 22:19 ward-kdl.topology.kdl -rw-r--r-- 1 root root 1908 Jul 8 22:19 ward-kdl.trello.guardfile.kdl ──────────────────────────────────────── ▸ shell command: cat /substrate/ward/.ward/ward-kdl/ward-kdl.defaults.kdl smart-defaults { agent-reservation-ttl "1h" agent-reservation-recheck-max "15s" agent-reap-idle "1h" agent-reap-max-cpu "5.0" director-max-parallel "10" director-limit "50" director-poll-interval "30s" reviewer-timeout "8m" config-bundle-ttl "600" container-assets-ttl "1h" container-read-only-extra-repo-ttl "24h" container-reap-keep "10" // TODO: move advisor depth budgets and container-research setup budget. } ──────────────────────────────────────── ▸ shell command: grep -r "agent-workflow" /substrate/ward/.ward/ward-kdl/ || echo "No agent-workflow found" No agent-workflow found ──────────────────────────────────────── ▸ shell command: cat /substrate/ward/.ward/ward-kdl/ward-kdl.fleet.kdl // Fleet config for ward (cli-guard fleetconfig, DIALECT 2). This is NOT a // guardfile: it names which agents the ward fleet can run and how each one is // launched (binary, context level, argv shape, model), never a permission. The // `.fleet.kdl` suffix - no `.guardfile.` infix - keeps it out of the ward-kdl // guardfile auto-discovery glob (ward-kdl.*.guardfile.kdl) and the exec/ops // mirrors; it rides its own embed dir (cmd/ward/fleetassets/) and parser // (cmd/ward/fleet.go via pkg/fleetconfig), legibly partitioned from the // permission dialect (aos#310 §6, ward#415). // // This file is the single hand-edited source. `make sync-fleet-assets` copies // it to cmd/ward/fleetassets/fleet.generated.kdl for go:embed (which cannot // reach this sibling dir); fleetassets_test.go fails the build on drift. // // This is the single source of the roster + per-agent divergence, feeding the // container_bootstrap.go env-defaults, restated in the ratified fleet grammar. // ward#419 deleted the old agent-adapters.yaml mirror, collapsing the ward#415 // three-way pin to a two-way one: the contract test (agent_adapter_test.go, // TestFleetSwitchesTwoWayPin) pins fleet.generated.kdl <-> the parseMode roster. // // POST-#412 roster: `opencode` is the canonical harness key (qwen is only the // backing model + a deprecated --mode alias). The runtime reads this manifest // (bootstrap defaults + the launcher-facing projection in agent_adapter.go). fleet { schema-version 2 // defaults mirror the container_bootstrap.go env-default constants: WARD_MODE // -> defaults.agent, WARD_GIT_NAME/WARD_GIT_EMAIL -> defaults.attribution. defaults { agent claude attribution name=coilyco-ops email=coilyco-ops@coilysiren.me } // claude: full context (2), stream-json headless, keychain auth. model / // reasoning-effort are override-only (ward#616): empty defaults keep bare launch. agent claude { binary claude context-level 2 stream stream-json auth claude-keychain model "" reasoning-effort "" argv { preflight claude -p headless claude -p --verbose --output-format stream-json interactive claude } } // codex: scoped context (level 1), no stream, codex-file auth, no pre-flight. agent codex { binary codex context-level 1 stream none auth codex-file model gpt-5.4 reasoning-effort medium verbosity low argv { headless codex exec interactive codex } } // opencode: minimal context (level 0), no stream, no host auth, no pre-flight. agent opencode { binary opencode context-level 0 stream none auth none model qwen3-coder:30b endpoint "http://localhost:11434/v1" argv { headless opencode run interactive opencode } } // goose: full context (level 2) like claude, no stream, ollama auth. agent goose { binary goose context-level 2 stream none auth ollama argv { preflight goose run -t headless goose run -t interactive goose session } } // Per-role capability roster (ward#578) + per-agent model/effort overlay // (cli-guard#192, ward#620); overlay precedence in docs/agent-config-overrides.md. roles { // engineer: no host reach; a cheaper model for parallel fan-out (ward#620). role engineer { agent claude { model claude-fable-5 reasoning-effort medium } agent codex { model gpt-5.4-mini reasoning-effort medium } } // director mirrors advisor's live-observe set (aws + tailnet, ward#547); its // heartbeat wants the strongest model at 1M context (ward#620). role director { guardfiles ward-kdl.aws.guardfile.kdl ward-kdl.tailscale.guardfile.kdl agent claude { model "claude-opus-4-8[1m]" reasoning-effort high } agent codex { model gpt-5.5 reasoning-effort medium } } // advisor does live-observe research: the aws SSM read + the tailnet route. // `advisor --no-tailnet` opts a rare isolated run back out. role advisor { guardfiles ward-kdl.aws.guardfile.kdl ward-kdl.tailscale.guardfile.kdl } } } ──────────────────────────────────────── ▸ shell command: find /substrate/ward -name "*.md" -exec grep -l "smart-defaults\|workflow.*policy" {} \; /substrate/ward/README.md /substrate/ward/docs/troubleshooting.md /substrate/ward/docs/agent-workflow.md /substrate/ward/docs/agent-director-dispatch.md /substrate/ward/docs/FEATURES.md /substrate/ward/docs/agent-reservation.md /substrate/ward/docs/config-source.md /substrate/ward/docs/container-cleanup.md /substrate/ward/docs/agent-reserved-immutable.md /substrate/ward/docs/agent.md ──────────────────────────────────────── ▸ shell command: cat /substrate/ward/docs/agent-workflow.md --- doc_goal: Let an operator pick the right per-run landing policy - direct-main, pr, or patch-only - by trust level and understand exactly what each mode changes in the seed, container env/label, and reaper gate, including the honest first-slice limits like the still-push-capable token. --- # ward agent: workflow modes `--workflow` picks a dispatched engineer's **landing policy** - how the run is allowed to turn finished work into a landed change ([ward#508](https://forgejo.coilysiren.me/coilyco-flight-deck/ward/issues/508)). One run, one container, one issue; the workflow decides only *how it lands*, not *what it builds*. ```bash warded engineer #98 --workflow direct-main # (default) merge to main, push, close warded engineer #98 --workflow pr # branch + pull request; a human merges warded engineer #98 --workflow patch-only # produce a patch, land nothing ``` The default is `direct-main`, so an unflagged run behaves exactly as it always has. The mode is visible in `--print` output, rides the container as the `WARD_WORKFLOW` env var and a `ward.workflow` label, and is read by the reaper. ## The three modes - **`direct-main`** *(default)* - the fast path: implement, commit, merge to `main`, push, and close the issue with a `closes #N` trailer. Intended for solo repos, trusted automation, and low-review surfaces. On **GitHub** (whose `main` is typically protected) `direct-main` already lands via a pull request - the forge decides, so the two collapse there. - **`pr`** - carry the work to a **branch and a pull request** instead of landing on `main` directly. The PR is the merge gate; a human or a follow-up loop lands it. The seed tells the agent to push the branch and open the PR, and **not** to push `main`. - **`patch-only`** - the run has **no landing authority**: it commits locally but produces a **patch** (`git format-patch origin/main --stdout`) and posts it in a comment for a human to review and apply. It neither pushes `main` nor opens a PR, and writes no `closes #N` trailer. Intended for untrusted targets, experiments, and high-risk work. ## Which mode for which trust level - **High trust** (your own repo, an automation repo you own) - `direct-main`. - **Shared / reviewed** (a team repo where changes get looked at) - `pr`. - **Low trust / exploratory** (an external target, a risky change you want to eyeball before it touches the tree) - `patch-only`. ## What the mode actually changes - **Seed prompt / done-condition.** The carry clause and the closing retrospective's "only after ..." landing phrase both shift with the mode, so a `patch-only` run is never told to merge to `main`, and a `pr` run is never told to push it. See [agent.md](agent.md) for the seed shape. - **Container env + label.** A non-default run exports `WARD_WORKFLOW=<mode>` and wears a `ward.workflow=<mode>` label; `direct-main` omits both. - **The reaper.** `ward container reap` normally force-lands residual work on `main` at teardown. For a `pr`/`patch-only` run it reads `WARD_WORKFLOW` and **refuses to push `main`**, preserving any residual work on a `ward-salvage/<id>` branch instead. See [container-reap.md](container-reap.md). ## Rough edges (first slice) This first slice is deliberately minimal: - `patch-only` is enforced at the **prompt + reaper** layer, not the credential layer: the container still carries a push-capable token. Hard credential scoping (a read-only token) is the deferred "read-only credential hardening". - A `pr`/`patch-only` run's residual local commits are preserved on a salvage branch by the reaper (safe, but noisier than a dedicated "held" outcome). - The autonomous [pre-flight](agent-preflight.md) still reads in merge-to-main terms; it judges feasibility, not the landing contract, so it is left as-is. ## See also - [agent.md](agent.md) - the `ward agent` verb family and the seed prompt. - [container-reap.md](container-reap.md) - the teardown reaper the workflow gates. - [agent-github.md](agent-github.md) - the GitHub lane, where `direct-main` already lands via a PR. ──────────────────────────────────────── ▸ shell command: cat /substrate/ward/docs/config-source.md --- doc_goal: Pin the WARD_CONFIG_REF config-source seam - the fs.FS the KDL build sites compile from, the unset-means-baked selection contract, the flat bundle layout, and the per-site degrade behavior. --- # The config source: `WARD_CONFIG_REF` and the fs.FS-at-launch seam Since [ward#653](https://forgejo.coilysiren.me/coilyco-flight-deck/ward/issues/653) (epic [ward#650](https://forgejo.coilysiren.me/coilyco-flight-deck/ward/issues/650)), ward's KDL surfaces compile at launch from a selected `fs.FS`, not a hard-wired embed. `cmd/ward/configsource.go` picks it. Four sites read it: - `ward ops forgejo` - spec guardfile + swagger lock, plus the optional admin guardfile. - the exec-dialect auto-mount - `ward docker`, `ward agents <tool>`, `ward ops {aws,kubectl,...}`. - the fleet roster - dialect-2 `fleetconfig.Parse`. - the smart-defaults bundle - runtime policy defaults in `cmd/ward/smartdefaults.go`. ## Selection contract - **Unset** - the baked neutral default: the embedded mirrors of `.ward/ward-kdl/` (drift-tested). - **`file://<dir>`** - `os.DirFS(<dir>)` over a local bundle directory in the flat layout below. - **`<host>/<owner>/<repo>[@<ref>]//<subpath>`** - the git-ref grammar, synced through the TTL-cached resolver ([config-ref-resolver.md](config-ref-resolver.md)). ## Bundle layout A ref points at a **flat** bundle directory - the [aos#332](https://github.com/coilysiren/agentic-os/issues/332) layout, same as `.ward/ward-kdl/`: - `ward-kdl.forgejo.guardfile.kdl` + `forgejo.swagger.lock.json` - the spec surface for `ops forgejo`. - `ward-kdl.<area>.guardfile.kdl` (exec dialect) - auto-mounted at their `wrap` path ([ward-kdl-in-ward.md](ward-kdl-in-ward.md)); the exec scan mounts only files carrying an `exec` block. - `ward-kdl.fleet.kdl` - the dialect-2 fleet manifest. - `ward-kdl.defaults.kdl` - the launch-selected smart defaults for runtime policy knobs like reservation TTL, director cadence, and container retention. - `ward-kdl.topology.kdl` - container topology overlay. Env wins. - `forgejo-admin.guardfile.kdl` - **optional**; omitting it withholds `ops forgejo admin/doctor`. ## Failure behavior A set-but-unresolvable ref and a bundle that fails to parse both degrade **per site, loudly**: - `ward ops forgejo` mounts the error leaf - the failure surfaces on invocation (`guardfile runtime failed to mount: ...`), so a bad bundle can never silently drop a verb surface. - the exec auto-mount degrades with a stderr warning at launch. - fleet consumers (`ward agents list`, `ward agent ...`) error at verb time. - smart-defaults consumers (`ward agent reap`, `ward agent director`, `ward agent review`, reservation/comment code paths, container cleanup) error at verb time. - the rest of the CLI (`version`, `exec`, `git`, ...) keeps working. There is no fallback from a named-but-broken source to the baked default. ## See also - [config-ref-resolver.md](config-ref-resolver.md) - the git-ref resolver. - [ward-kdl.md](ward-kdl.md) - the build-time authoring layer the bundle comes from. - [ward-kdl-in-ward.md](ward-kdl-in-ward.md) - how exec guardfiles auto-mount. - [config-discovery.md](config-discovery.md) - the same loud-override rule for the allowlist. ──────────────────────────────────────── ▸ shell command: ls -la /substrate/ward/docs/ | grep -E "(smart|default)" (no output) Command exited with code 1 ──────────────────────────────────────── ▸ shell command: find /substrate/ward -name "*.md" -exec grep -l "smart-defaults\|ward-kdl.defaults.kdl" {} \; /substrate/ward/docs/troubleshooting.md /substrate/ward/docs/ward-kdl.md /substrate/ward/docs/agent-director-dispatch.md /substrate/ward/docs/FEATURES.md /substrate/ward/docs/agent-reservation.md /substrate/ward/docs/config-source.md /substrate/ward/docs/container-cleanup.md /substrate/ward/docs/agent-reserved-immutable.md ──────────────────────────────────────── ▸ shell command: cat /substrate/ward/docs/ward-kdl.md | head -50 --- doc_goal: One answer to what ward-kdl is, how it differs from ward, and whether a repo needs a guardfile - build-time authoring layer vs run-time product. --- # ward-kdl: the build-time authoring layer **ward-kdl is the build-time authoring layer. `ward` is the run-time product that embeds what it authors. [cli-guard](https://forgejo.coilysiren.me/coilyco-flight-deck/cli-guard) is the engine both stand on.** Three roles, told apart by **when** they run. The conceptual model lives in [architecture.md](architecture.md). ## Do you need to author a guardfile? (start here) Almost certainly not. **A repo needs a guardfile only when it runs its own `ward ops` operator surface. Dev-verb adoption is `.ward/ward.yaml` and nothing else.** The fork every adopter hits first: - **Dev-verb gate** (`ward exec build/test/lint`, `ward git`, the audit log) on your repo: a committed [`.ward/ward.yaml`](../.ward/ward.yaml) is the whole contract, no guardfile. That surface is forge-agnostic and already embedded in the installed `ward`. See [ward-yaml.md](ward-yaml.md). - **Your own operator surface** (`ward ops forgejo/aws`, the fleet roster) against your own endpoints, tokens, and owner gate: only then a guardfile, and even then you **swap placeholders** in the neutral example bundle and rebuild from source. See [ward-kdl-authoring.md](ward-kdl-authoring.md) and the grammar in [guardfile-grammar.md](guardfile-grammar.md). Guardfiles are ward's own build-time internals, not a per-repo file a `ward exec` user maintains. ## Build time: source in, validated artifact out You author a source file, cli-guard compiles or validates it, `ward` embeds the result. Nothing is fetched at runtime. `ward-kdl` is `protoc` for permissions and fleet config, and you rarely run it by hand: you run what it produced and regenerate when the source changes (`make build-ward-kdl`). Three dialects: - **Dialect 1, permission surfaces** - `*.guardfile.kdl` spec + exec files. Least-privilege, audited. Parsed by `cli/execverb` + `http/specverb`. - **Dialect 2, fleet-config manifest** - `ward-kdl.fleet.kdl`: identity, model, endpoint, attribution, roster defaults, sparse overrides, `roles`. - **Dialect 3, operator-local** - the same `fleetconfig` parser, sourced from a local `~/.ward/fleet.local.kdl`, not embedded and tracked separately. - **Smart defaults bundle** - `ward-kdl.defaults.kdl`: launch-selected runtime policy defaults for reservation TTL, recheck cadence, reap thresholds, director cadence, and container retention. Parsed by ward at launch, embedded via `defaultsassets/`. ## Run time: `ward` embeds the emitted surfaces `ward` (public face `warded`) is the product a user installs. It embeds the ward-kdl surfaces as `ward ops <api>`, `ward docker`, `ward agents <target>`, then adds the run-time-only layers ward-kdl never produces: `ward agent` and `ward exec`. The embeds are the baked default: `WARD_CONFIG_REF` can select a live bundle at launch ([config-source.md](config-source.md)). Exec guardfiles auto-mount at their `wrap` path ([ward-kdl-in-ward.md](ward-kdl-in-ward.md)). ## The per-area reference docs Every guardfile gets a generated reference doc beside it, committed under [docs/ward-kdl/](ward-kdl/). Emitted by ward-kdl's `surface.Markdown()`, they describe one area's verbs. [ward-kdl-surface.md](ward-kdl-surface.md) is the flat index across every area. ## See also - [guardfile-grammar.md](guardfile-grammar.md) - the dialect-1 KDL grammar and a minimal guardfile. - [ward-kdl-authoring.md](ward-kdl-authoring.md) - getting the compiler, swapping the bundle. - [architecture.md](architecture.md) - the three-layer model (cli-guard / ward-kdl / ward). - [ward-kdl-surface.md](ward-kdl-surface.md) - the full generated verb surface, area by area. - [ward-kdl-in-ward.md](ward-kdl-in-ward.md) - how exec guardfiles auto-mount into `ward`. Cross-reference convention from [coilysiren/agentic-os#59](https://github.com/coilysiren/agentic-os/issues/59). ──────────────────────────────────────── ▸ shell command: grep -A 20 -B 5 "agent-workflow" /substrate/ward/docs/troubleshooting.md (no output) Command exited with code 1 ──────────────────────────────────────── ▸ shell command: grep -r "agent-workflow" /substrate/ward/docs/ /substrate/ward/docs/FEATURES.md:- **`--workflow direct-main|pr|patch-only`** *([ward#508](https://forgejo.coilysiren.me/coilyco-flight-deck/ward/issues/508))* - the dispatched engineer's **landing policy**: `direct-main` (default) merges to `main` and closes (unchanged); `pr` opens a branch + pull request; `patch-only` posts a patch with no landing authority. The mode shifts the seed, rides the container env + a `ward.workflow` label, and gates the reaper's `main` push. See [agent-workflow.md](agent-workflow.md). /substrate/ward/docs/agent.md:- [agent-workflow.md](agent-workflow.md) - `--workflow direct-main|pr|patch-only`, the run's landing policy. ──────────────────────────────────────── ▸ todo_write todo content: - [x] Analyze current KDL structures in agentic-os and ward repos - [x] Identify existing workflow configuration patterns - [x] Research smart-defaults schema from ward#707 (not yet implemented) - [x] Determine where to add the agent-workflow configuration - [x] Review issue requirements for the coilyco override - [x] Gather context on PR workflow dependencies: ward#706 and ward#707 ──────────────────────────────────────── ▸ shell command: curl -s "https://forgejo.coilysiren.me/api/v1/repos/coilyco-flight-deck/ward/issues/707" | grep -E "\"title\":\"|\"body\":\"" {"id":4200,"url":"https://forgejo.coilysiren.me/api/v1/repos/coilyco-flight-deck/ward/issues/707","html_url":"https://forgejo.coilysiren.me/coilyco-flight-deck/ward/issues/707","number":707,"user":{"id":7,"login":"coilyco-ops","login_name":"","source_id":0,"full_name":"Coilyco Robotic Operations Division","email":"coilyco-ops@noreply.forgejo.coilysiren.me","avatar_url":"https://forgejo.coilysiren.me/avatars/ed264a3b7b6770327da211496912cfff5bacae8ac8fa8a9748e3d5ea638b875e","html_url":"https://forgejo.coilysiren.me/coilyco-ops","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2026-06-18T03:44:21Z","restricted":false,"active":false,"prohibit_login":false,"location":"","pronouns":"ro / bot","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"coilyco-ops"},"original_author":"","original_author_id":0,"title":"Make agent workflow defaults configurable and default engineers to PRs","body":"## Goal\n\nMake ward's agent workflow selection config-driven, flip warded engineers to PR workflow by default, and support per-repo workflow overrides.\n\nThis is the configuration half of the direct-main to PR transition. It should land after or alongside the PR lifecycle work in ward#706, because defaulting to `pr` should mean the run can actually create the PR, wait for CI, and merge with a merge commit.\n\n## Current behavior\n\n* `cmd/ward/agent_workflow.go` has `defaultWorkflow = workflowDirectMain`.\n* `workflowFlag()` exposes `--workflow` with a hard-coded `direct-main` default.\n* `agentWorkflow()` only parses the CLI flag.\n* `container_compute.go` omits `WARD_WORKFLOW` and the `ward.workflow` label for default/direct-main runs.\n* `docs/agent-workflow.md` documents direct-main as the default.\n* Runtime policy KDL currently lives in `ward-kdl.defaults.kdl` under `smart-defaults`, but it has no workflow policy nodes.\n\n## Desired behavior\n\n* The built-in ward default becomes `pr`.\n* `smart-defaults` KDL can set the default workflow.\n* `smart-defaults` KDL can override workflow by repo, keyed by owner/repo.\n* CLI `--workflow` still wins over config.\n* Repo override wins over fleet/default workflow.\n* Invalid configured workflow values fail closed with a useful error.\n* Dry-run/print output, reservation records, container env/labels, seed prompts, docs, and tests all show the resolved workflow.\n* Existing explicit `--workflow direct-main` and `--workflow patch-only` behavior keeps working.\n\n## Sketch\n\nOne plausible KDL shape:\n\n```kdl\nsmart-defaults {\n agent-workflow default=\"pr\" {\n repo \"coilyco-flight-deck/agentic-os\" workflow=\"direct-main\"\n repo \"coilyco-flight-deck/ward\" workflow=\"pr\"\n }\n}\n```\n\nUse the repo key that is already resolved by dispatch (`agentIssueRef.repoSlug()`), not cwd discovery, so bare refs and full refs behave the same.\n\n## Acceptance\n\n* Unit tests cover built-in default, KDL default, repo override, CLI precedence, invalid values, and env/label projection.\n* `docs/agent-workflow.md` is updated to describe PR as the default and config override precedence.\n* `docs/FEATURES.md` is updated if this changes the feature inventory.","ref":"","assets":[],"labels":[],"milestone":null,"assignee":null,"assignees":null,"state":"open","is_locked":false,"comments":1,"created_at":"2026-07-08T22:12:40Z","updated_at":"2026-07-08T22:19:00Z","closed_at":null,"due_date":null,"pull_request":null,"repository":{"id":4,"name":"ward","owner":"coilyco-flight-deck","full_name":"coilyco-flight-deck/ward"},"pin_order":0} ──────────────────────────────────────── ▸ shell command: curl -s "https://forgejo.coilysiren.me/api/v1/repos/coilyco-flight-deck/ward/issues/706" | grep -E "\"title\":\"|\"body\":\"" {"id":4199,"url":"https://forgejo.coilysiren.me/api/v1/repos/coilyco-flight-deck/ward/issues/706","html_url":"https://forgejo.coilysiren.me/coilyco-flight-deck/ward/issues/706","number":706,"user":{"id":7,"login":"coilyco-ops","login_name":"","source_id":0,"full_name":"Coilyco Robotic Operations Division","email":"coilyco-ops@noreply.forgejo.coilysiren.me","avatar_url":"https://forgejo.coilysiren.me/avatars/ed264a3b7b6770327da211496912cfff5bacae8ac8fa8a9748e3d5ea638b875e","html_url":"https://forgejo.coilysiren.me/coilyco-ops","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2026-06-18T03:44:21Z","restricted":false,"active":false,"prohibit_login":false,"location":"","pronouns":"ro / bot","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"coilyco-ops"},"original_author":"","original_author_id":0,"title":"Make PR workflow create, wait, and merge pull requests","body":"## Goal\n\nChange `--workflow pr` from a branch-and-human-gate prompt into a complete ward landing workflow for Forgejo engineers.\n\nToday PR workflow only tells the container agent to push a branch and open a pull request, then it stops. The requested default change needs PR mode to be a real autonomous path first: create the PR, wait for Forgejo Actions or required status checks to finish, run the existing review gate after CI is green, then merge the PR with a merge commit.\n\n## Context read before filing\n\n* `cmd/ward/agent_workflow.go` currently documents `pr` as branch + PR with a human or follow-up loop landing it.\n* `docs/agent-workflow.md` says the same and names this as a first-slice limitation.\n* `docs/ward-kdl/ward-kdl.forgejo.write.guardfile.md` currently denies PR view/list and says PRs are read through the web UI.\n* The Forgejo swagger lock already contains pull request, action task, branch protection, and merge related shapes, so this is a product/guarded-surface gap rather than an API absence.\n\n## Desired behavior\n\n* Forgejo `pr` workflow opens a real pull request against `main` from the feature branch.\n* Ward waits for CI/status checks for that PR branch/head before review and merge.\n* Ward runs the existing in-container review gate only after CI is green.\n* Ward merges with a merge commit, not squash, rebase, or fast-forward.\n* The issue close path is preserved through the PR body or merge commit message using `closes #N`.\n* Failure to create the PR, green CI, pass review, or merge is reported as blocked/failed with useful context on the issue.\n* GitHub behavior stays compatible with the existing GitHub PR lane.\n\n## Notes\n\nThis should not rely on the agent improvising hidden `curl` calls. Prefer a ward-owned helper or guarded Forgejo verbs with tests around request shape, polling behavior, and failure classification.","ref":"","assets":[],"labels":[],"milestone":null,"assignee":null,"assignees":null,"state":"open","is_locked":false,"comments":1,"created_at":"2026-07-08T22:12:26Z","updated_at":"2026-07-08T22:13:05Z","closed_at":null,"due_date":null,"pull_request":null,"repository":{"id":4,"name":"ward","owner":"coilyco-flight-deck","full_name":"coilyco-flight-deck/ward"},"pin_order":0}{"summary":"## Summary\n\nThis issue is about updating the aos-authored ward KDL bundle to override the default workflow for the coilyco deployment while keeping ward itself configured to use PR workflow by default. Based on the context and the referenced issues (ward#706 and ward#707), I've analyzed the configuration structure required.\n\n## Analysis\n\nFrom my research, I identified that:\n\n1. **Current State**: The `ward-kdl.defaults.kdl` file in `ward` repo currently contains only basic smart-defaults configuration but lacks workflow configuration capabilities\n2. **Required Changes**: Once ward#707 (smart-defaults schema for workflow) lands, the agentic-os KDL bundle needs to be updated to set agent-workflow default as \"direct-main\" while specifically overriding the coilyco-flight-deck/ward repo to use \"pr\"\n3. **Configuration Location**: The aos bundle should modify `.ward/ward-kdl.defaults.kdl` (or equivalent) to add the workflow configuration\n4. **Schema**: Based on the ward#707 issue description, the expected KDL shape is:\n```kdl\nsmart-defaults {\n agent-workflow default=\"direct-main\" {\n repo \"coilyco-flight-deck/ward\" workflow=\"pr\"\n }\n}\n```\n\n## Risk Assessment\n\n- **Dependency Risk**: This change is dependent on ward#707 landing first to implement the smart-defaults schema for agent-workflow configuration. Without this, the configuration will not parse correctly.\n- **Compatibility Risk**: The PR workflow lifecycle (ward#706) must be fully implemented so that coilyco-flight-deck/ward can successfully go through full PR creation, CI wait, review, and merge lifecycle.\n- **Timing Risk**: If agentic-os makes changes before ward#707 is implemented, the KDL will fail to parse during ward's startup.\n\n## Recommendation\n\nThis should be implemented AFTER ward#707 lands with implementation of the smart-defaults schema for agent workflow. The change should be limited to modifying the `.ward/ward-kdl.defaults.kdl` file inside the agentic-os repository, with validation that it parses correctly using `pre-commit run --all-files` or `ward exec` as specified in the issue acceptance criteria.", "issues": [{"repo": "coilyco-flight-deck/ward", "title": "Make agent workflow defaults configurable and default engineers to PRs", "body": "## Goal\n\nMake ward's agent workflow selection config-driven, flip warded engineers to PR workflow by default, and support per-repo workflow overrides.\n\nThis is the configuration half of the direct-main to PR transition. It should land after or alongside the PR lifecycle work in ward#706, because defaulting to `pr` should mean the run can actually create the PR, wait for CI, and merge with a merge commit.\n\n## Current behavior\n\n* `cmd/ward/agent_workflow.go` has `defaultWorkflow = workflowDirectMain`.\n* `workflowFlag()` exposes `--workflow` with a hard-coded `direct-main` default.\n* `agentWorkflow()` only parses the CLI flag.\n* `container_compute.go` omits `WARD_WORKFLOW` and the `ward.workflow` label for default/direct-main runs.\n* `docs/agent-workflow.md` documents direct-main as the default.\n* Runtime policy KDL currently lives in `ward-kdl.defaults.kdl` under `smart-defaults`, but it has no workflow policy nodes.\n\n## Desired behavior\n\n* The built-in ward default becomes `pr`.\n* `smart-defaults` KDL can set the default workflow.\n* `smart-defaults` KDL can override workflow by repo, keyed by owner/repo.\n* CLI `--workflow` still wins over config.\n* Repo override wins over fleet/default workflow.\n* Invalid configured workflow values fail closed with a useful error.\n* Dry-run/print output, reservation records, container env/labels, seed prompts, docs, and tests all show the resolved workflow.\n* Existing explicit `--workflow direct-main` and `--workflow patch-only` behavior keeps working.\n\n## Sketch\n\nOne plausible KDL shape:\n\n```kdl\nsmart-defaults {\n agent-workflow default=\"pr\" {\n repo \"coilyco-flight-deck/agentic-os\" workflow=\"direct-main\"\n repo \"coilyco-flight-deck/ward\" workflow=\"pr\"\n }\n}\n```\n\nUse the repo key that is already resolved by dispatch (`agentIssueRef.repoSlug()`), not cwd discovery, so bare refs and full refs behave the same.\n\n## Acceptance\n\n* Unit tests cover built-in default, KDL default, repo override, CLI precedence, invalid values, and env/label projection.\n* `docs/agent-workflow.md` is updated to describe PR as the default and config override precedence.\n* `docs/FEATURES.md` is updated if this changes the feature inventory."}, {"repo": "coilyco-flight-deck/ward", "title": "Make PR workflow create, wait, and merge pull requests", "body": "## Goal\n\nChange `--workflow pr` from a branch-and-human-gate prompt into a complete ward landing workflow for Forgejo engineers.\n\nToday PR workflow only tells the container agent to push a branch and open a pull request, then it stops. The requested default change needs PR mode to be a real autonomous path first: create the PR, wait for Forgejo Actions or required status checks to finish, run the existing review gate after CI is green, then merge the PR with a merge commit.\n\n## Context read before filing\n\n* `cmd/ward/agent_workflow.go` currently documents `pr` as branch + PR with a human or follow-up loop landing it.\n* `docs/agent-workflow.md` says the same and names this as a first-slice limitation.\n* `docs/ward-kdl/ward-kdl.forgejo.write.guardfile.md` currently denies PR view/list and says PRs are read through the web UI.\n* The Forgejo swagger lock already contains pull request, action task, branch protection, and merge related shapes, so this is a product/guarded-surface gap rather than an API absence.\n\n## Desired behavior\n\n* Forgejo `pr` workflow opens a real pull request against `main` from the feature branch.\n* Ward waits for CI/status checks for that PR branch/head before review and merge.\n* Ward runs the existing in-container review gate only after CI is green.\n* Ward merges with a merge commit, not squash, rebase, or fast-forward.\n* The issue close path is preserved through the PR body or merge commit message using `closes #N`.\n* Failure to create the PR, green CI, pass review, or merge is reported as blocked/failed with useful context on the issue.\n* GitHub behavior stays compatible with the existing GitHub PR lane.\n\n## Notes\n\nThis should not rely on the agent improvising hidden `curl` calls. Prefer a ward-owned helper or guarded Forgejo verbs with tests around request shape, polling behavior, and failure classification."}] --- Researched and posted automatically by `ward agent advisor --harness goose` (ward#179). This is one-shot research, not a carried change - verify before acting on it. <!-- ward-agent-reply --> <!-- ward-agent-signature --> — Goose, via `ward agent`
Author
Member

WARD-RESERVATION: held 🔒

reservation details

Holder: container engineer-codex-agentic-os-345 on host kais-macbook-pro-2.local.

Reserved by ward agent --harness codex (reserved 2026-07-09T21:32:53Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (1h TTL). --force overrides.

Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh. That is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).

run seed context — what this run is carrying (ward#609)
  • Resolved: coilyco-flight-deck/agentic-os#345 · branch issue-345 · harness codex · workflow direct-to-main
  • Run: engineer-codex-agentic-os-345 · ward v0.493.0 · dispatched 2026-07-09T21:32:53Z
  • Comment thread: 1 included in the pre-flight read, 0 stripped (ward's own automated comments).

Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.493.0).

— Codex, via ward agent

<!-- ward-agent-reservation --> WARD-RESERVATION: held 🔒 <details><summary>reservation details</summary> Holder: container `engineer-codex-agentic-os-345` on host `kais-macbook-pro-2.local`. Reserved by `ward agent --harness codex` (reserved 2026-07-09T21:32:53Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (1h TTL). `--force` overrides. **Do not comment on or edit this issue to steer the run while it is reserved.** The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a **new issue, dispatched fresh**. That is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494). <details><summary>run seed context — what this run is carrying (ward#609)</summary> - **Resolved:** `coilyco-flight-deck/agentic-os#345` · branch `issue-345` · harness `codex` · workflow `direct-to-main` - **Run:** `engineer-codex-agentic-os-345` · ward `v0.493.0` · dispatched `2026-07-09T21:32:53Z` - **Comment thread:** 1 included in the pre-flight read, 0 stripped (ward's own automated comments). - included: @coilyco-ops (2026-07-08T22:20:30Z) Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.493.0). </details> </details> <!-- ward-agent-signature --> — Codex, via `ward agent`
Author
Member

WARD-OUTCOME: done

details

workflow: direct-main; review summary: skipped by ~/.ward/config.yaml default
implementation felt: straightforward bundle/docs/test update, with one merge detour for upstream docs.
confidence: high
surprises: the remote main advanced during the run, and the Go caches were initially too full to let the hooks build.
follow-ups: none

WARD-OUTCOME: done ✅ <details><summary>details</summary> workflow: direct-main; review summary: skipped by ~/.ward/config.yaml default implementation felt: straightforward bundle/docs/test update, with one merge detour for upstream docs. confidence: high surprises: the remote main advanced during the run, and the Go caches were initially too full to let the hooks build. follow-ups: none </details>
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/agentic-os#345
No description provided.