Skip to content

feat(subagents): profile discovery tool + built-in default profile (local_write) - #163

Merged
jkyberneees merged 3 commits into
mainfrom
feat/subagent-profile-selection
Aug 31, 2026
Merged

feat(subagents): profile discovery tool + built-in default profile (local_write)#163
jkyberneees merged 3 commits into
mainfrom
feat/subagent-profile-selection

Conversation

@jkyberneees

Copy link
Copy Markdown
Contributor

Summary

Closes the two operator-facing gaps in sub-agent capability profiles (P4):

  1. The model had no way to discover profiles. delegate_tasks accepts a profile name, but names live only in the operator's config. New built-in list_subagent_profiles tool renders the resolved profiles map — name, description, max_risk, tool filters, is_default, plus the effective default_profile — so the model picks by intent, not by guessing.
  2. No default envelope. A built-in default profile (max_risk: "local_write") is applied to any delegated sub-agent that selects nothing, overridable via the new subagent.default_profile key (or disabled with "none").

Behavior change (deliberate, please review)

Trusted sub-agents were previously uncapped; they are now clamped to local_write by the default envelope. The envelope is applied before the P2/P3 trust lockdown, which still cannot be lifted by profile selection. Tasks needing code_execution/network_egress must select an explicit profile (e.g. test-runner, researcher). Operators can restore the old behavior with subagent.default_profile: "none".

Details

  • ProfileConfig.description (optional): model-readable intent per profile; added to all 21 entries in profiles.template.json.
  • Precedence: --profile flag > task-file profile > subagent.default_profile (built-in default).
  • Fail-closed everywhere: unknown names fail the task parent-side (pre-spawn) and child-side; a broken default_profile fails the sub-agent at spawn, loudly; "none" is honored only from operator config — a task file or flag can never strip the operator's envelope.
  • Project-level odek.json cannot set default_profile (whole subagent section stays operator-only).
  • Global config template now scaffolds subagent.default_profile: "default" so the default is stated in the config itself.
  • Docs: CONFIG.md (new "Built-in default profile" section), SECURITY.md (envelope semantics, pinned-by list), SUBAGENTS.md, profiles.template.json.

Testing

  • RED-first per milestone: cmd/odek/profiles_tool_test.go (6 tests), cmd/odek/subagent_profiles_test.go (+5: built-in selectable, broken default fail-closed, "none" opt-out, explicit-task precedence, trusted-child clamp pin), internal/config/subagent_config_test.go (+3: resolution, injection/override/disabled, project rejection).
  • Full cmd/odek + internal/config suites green (-count=1); -race green on profile/subagent scope; go build ./... + go vet clean.

The delegate_tasks schema accepts a profile name, but names only exist in
the operator's config — the model had no way to discover them. This adds:

- list_subagent_profiles built-in tool: renders the resolved profiles map
  (name, description, max_risk, tool filters, is_default) plus the
  effective default_profile, sorted; read-only over operator config.
- ProfileConfig.description: model-readable intent summary per profile.
- SubagentConfig/Resolved .default_profile field (behavior lands with the
  built-in default profile in the follow-up commit).
- delegate_tasks profile param now points at the discovery tool.
…l_write

Delegated sub-agents now run under a default capability envelope unless
something more specific is selected:

- Built-in "default" profile (max_risk: local_write) is materialized by
  the config pipeline unless the operator defines their own profile with
  that name or opts out via subagent.default_profile="none".
- New subagent.default_profile config key (operator-controlled, rejected
  from project-level odek.json like the rest of the section) points the
  default at any defined profile; an unknown name fails closed at spawn.
- Precedence: --profile flag > task-file profile > default envelope.
  "none" is honored only from operator config — a task file or flag can
  never strip the operator's envelope.
- Behavior change, deliberate: trusted sub-agents are now clamped to
  local_write too (the envelope is applied before the P2/P3 trust
  lockdown, which still cannot be lifted by profile selection). Tasks
  needing code_execution/network_egress must select an explicit profile.
- The built-in envelope is visible through list_subagent_profiles with
  an is_default marker and a model-readable description.
- CONFIG.md: subagent.default_profile row, description field, new
  'Built-in default profile' section (precedence, operator-only opt-out,
  trusted-clamp behavior change, list_subagent_profiles discovery).
- SECURITY.md: default-envelope semantics (built-in local_write cap also
  binds trusted sub-agents, 'none' honored only from operator config),
  updated pinned-by test list and fail-closed/residual-risk notes.
- SUBAGENTS.md: default-envelope paragraph in the profiles section.
- profiles.template.json: model-readable description on all 21 starter
  profiles (consumed by list_subagent_profiles).
- Global config template: scaffold subagent.default_profile: "default"
  so the operator-visible default is stated in the config itself.
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
odek 82d784e Commit Preview URL

Branch Preview URL
Aug 31 2026, 07:13 AM

@jkyberneees
jkyberneees merged commit 03c3ef5 into main Aug 31, 2026
10 checks passed
@jkyberneees
jkyberneees deleted the feat/subagent-profile-selection branch August 31, 2026 07:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant