feat(subagents): profile discovery tool + built-in default profile (local_write) - #163
Merged
Merged
Conversation
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.
Deploying with
|
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes the two operator-facing gaps in sub-agent capability profiles (P4):
delegate_tasksaccepts a profile name, but names live only in the operator's config. New built-inlist_subagent_profilestool renders the resolved profiles map — name,description,max_risk, tool filters,is_default, plus the effectivedefault_profile— so the model picks by intent, not by guessing.defaultprofile (max_risk: "local_write") is applied to any delegated sub-agent that selects nothing, overridable via the newsubagent.default_profilekey (or disabled with"none").Behavior change (deliberate, please review)
Trusted sub-agents were previously uncapped; they are now clamped to
local_writeby the default envelope. The envelope is applied before the P2/P3 trust lockdown, which still cannot be lifted by profile selection. Tasks needingcode_execution/network_egressmust select an explicit profile (e.g.test-runner,researcher). Operators can restore the old behavior withsubagent.default_profile: "none".Details
ProfileConfig.description(optional): model-readable intent per profile; added to all 21 entries inprofiles.template.json.--profileflag > task-fileprofile>subagent.default_profile(built-indefault).default_profilefails 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.odek.jsoncannot setdefault_profile(wholesubagentsection stays operator-only).subagent.default_profile: "default"so the default is stated in the config itself.Testing
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).cmd/odek+internal/configsuites green (-count=1);-racegreen on profile/subagent scope;go build ./...+go vetclean.