Status: Proposed
Audience: Forge, Rustic UI, and platform reviewers
Last updated: 2026-03-27
Primary scope: rustic-go and rustic-ui, with canonical behavior references in rustic-ai
This document proposes a first-class requirements model for agents and dependency
providers without adding setup metadata to AgentSpec.
The core recommendation is:
- keep
AgentSpecas the guild/runtime configuration object - introduce
AgentNeedskeyed by agentclass_name - introduce
DependencyNeedskeyed by dependency providerclass_name - compute effective needs by combining agent-class needs and resolved dependency-provider needs
- expose those effective needs to the UI with satisfaction state and required user actions
This design supports:
- showing users what an agent can access before launch
- prompting for missing secrets
- prompting for OAuth connection when needed
- prompting for capability approval such as network or filesystem access
- avoiding provider-specific secret names in generic agent specs
- Let the UI show agent setup requirements before launch.
- Keep
AgentSpecfree of setup-only requirements. - Support agent-class requirements and dependency-provider requirements.
- Support provider-specific needs such as OpenAI vs Gemini keys.
- Support user-facing actions for:
- add secret
- connect OAuth account
- approve filesystem access
- approve network access
- Support merging and deduplicating needs across a guild.
- Preserve existing launch-time secret injection and capability enforcement flows.
- This document does not redesign
AgentSpecas a resolved plan object. - This document does not store raw secret values in guild specs.
- This document does not define full cloud tenancy and RBAC behavior.
- This document does not replace the existing registry runtime model.
- This document does not define every OAuth provider adapter in detail.
Forge currently has pieces of the requirement model spread across different surfaces:
AgentSpec.Resources.SecretsAgentSpec.DependencyMap- registry entry fields such as
Secrets,Network, andFilesystem - external secret providers and injected environment variables
This is not a good user-facing setup model because:
AgentSpecis a runtime launch object, not a setup contract- provider-specific requirements are not tied cleanly to the selected dependency implementation
- the UI does not have a single object describing missing vs satisfied setup needs
- secrets, OAuth login, network access, and filesystem grants are conceptually different but are not modeled consistently
Example:
LLMAgentdepends on an abstractllmdependency- if
llmis satisfied byOpenAILLM, the effective setup needs are:OPENAI_API_KEY- network access to
api.openai.com
- if
llmis satisfied byGeminiLLM, the effective setup needs are:GEMINI_API_KEY- network access to Google AI endpoints
Those needs belong to the selected dependency provider, not to the generic
LLMAgent runtime spec.
- Keep runtime configuration separate from setup requirements.
- Express setup requirements declaratively and by class identity.
- Make dependency-provider requirements composable.
- Make effective needs deterministic from guild configuration plus dependency selection.
- Never store raw secret values in needs metadata.
- Let the UI render needs and actions without inferring from env vars.
- Preserve least privilege by showing and enforcing concrete capabilities.
AgentSpec remains part of GuildSpec and continues to describe:
- class name
- properties
- dependency bindings
- resources used for scheduling/runtime
- topics, predicates, and QoS
AgentSpec should not become the primary place for:
- secret declarations
- OAuth requirements
- user-facing capability prompts
Introduce a catalog object keyed by agent class_name.
AgentNeeds describes setup and capability needs inherent to the agent class
itself, independent of which guild is using it.
Examples:
- Browser agent needs browser capability and external network access
- DB agent needs filesystem access to a chosen project path
- Cache agent may require nothing external
Introduce a catalog object keyed by dependency provider class_name.
DependencyNeeds describes setup and capability needs contributed by a specific
dependency implementation.
Examples:
OpenAILLMneedsOPENAI_API_KEYandapi.openai.comGeminiLLMneedsGEMINI_API_KEYand Google endpointsGithubOAuthClientneeds GitHub OAuth scopes and a connected account
For a given guild launch, Forge computes:
EffectiveNeeds = AgentNeeds(agent.class_name) + DependencyNeeds(each resolved dependency provider class_name)
This merged object is what the UI and preflight checks consume.
Each Needs object should support the following categories:
secretsoauthcapabilitiesnetworkfilesystem
Compute resources such as CPU and GPU remain part of resources, not setup
needs.
Secrets are references by key name only.
Example:
secrets:
- key: OPENAI_API_KEY
label: OpenAI API Key
required: trueSemantics:
keyis the lookup key in the secret storelabelis the UI-facing label
OAuth needs represent connected-account requirements, not raw token material.
Example:
oauth:
- provider: google
label: Google Account
scopes:
- gmail.readonlySemantics:
- if the account is not connected, the UI shows
Connect - if connected but missing scopes, the UI shows
Reconnect
Capabilities are coarse approvals that the user can understand.
Example:
capabilities:
- type: network
label: External network access
- type: filesystem
label: Local filesystem accessThese are the user-facing capability summary. Fine-grained constraints live
under network and filesystem.
Network needs describe concrete host-level access.
Example:
network:
allow:
- api.openai.com
- generativelanguage.googleapis.comFilesystem needs describe concrete paths and modes.
Example:
filesystem:
allow:
- path: /home/user/code/project
mode: rwRecommended shape:
agent_needs:
- class_name: rustic_ai.browser.agent.BrowserAgent
needs:
capabilities:
- type: network
label: External network access
- type: filesystem
label: Local filesystem accessRecommended shape:
dependency_needs:
- class_name: rustic_ai.openai.llm.OpenAILLM
needs:
secrets:
- key: OPENAI_API_KEY
label: OpenAI API Key
network:
allow:
- api.openai.com
- class_name: rustic_ai.google.llm.GeminiLLM
needs:
secrets:
- key: GEMINI_API_KEY
label: Gemini API Key
network:
allow:
- generativelanguage.googleapis.comThe association is indirect:
AgentSpec.class_nameselectsAgentNeedsAgentSpec.dependency_mapresolves dependency providers- each resolved dependency provider
class_nameselectsDependencyNeeds
No needs are embedded directly into AgentSpec.
The resolver takes:
GuildSpec- agent registry entries
- dependency definitions
- agent needs catalog
- dependency needs catalog
- current secret/account/capability satisfaction state
For each agent:
- read
AgentSpec.class_name - load
AgentNeedsfor that class - inspect
AgentSpec.dependency_map - determine resolved dependency provider class names
- load
DependencyNeedsfor each provider - merge all needs into one effective per-agent set
- deduplicate by semantic key
- evaluate which needs are already satisfied
- attach UI actions for unsatisfied needs
- secrets dedupe by secret key
- OAuth dedupe by provider plus normalized scope set
- network dedupe by host entry
- filesystem dedupe by path plus mode
- capabilities dedupe by capability type
Conflicts should fail closed. Example:
- one provider requires read-only path
- another provider requires read-write path
The merged result should use the stricter or broader rule according to explicit policy, not silently guess.
The UI does not need just the declared needs. It needs status.
Each effective need should resolve to one of:
satisfiedmissingapproval_requiredreauth_requiredunsupported
Examples:
- secret key exists in the secret provider chain ->
satisfied - OAuth provider not connected ->
missing - network host requested but not approved ->
approval_required - OAuth account connected but scopes stale ->
reauth_required
Each unsatisfied need should map to a typed next action.
Examples:
provide_secretconnect_oauthreauthorize_oauthapprove_network_accessapprove_filesystem_access
Example resolved need:
{
"id": "secret:OPENAI_API_KEY",
"kind": "secret",
"label": "OpenAI API Key",
"status": "missing",
"action": {
"type": "provide_secret",
"secret_key": "OPENAI_API_KEY"
}
}Rustic UI should be able to render:
- what this agent can access
- which requirements come from the agent itself
- which requirements come from selected dependency providers
- what is already connected or approved
- what the user must do before launch
Recommended screens:
- per-agent
Needs - per-guild aggregated
Launch Requirements - settings pages for:
- secrets
- connected accounts
- capability approvals
This design is not only for display. It should also drive enforcement.
Recommended boundary:
- needs catalogs define expected requirements
- resolution computes effective needs
- preflight blocks launch on unsatisfied mandatory needs
- launch-time env and capability injection use the effective needs result
This allows the display model and enforcement model to stay aligned.
This proposal intentionally does not replace the following immediately:
registry.AgentRegistryEntry.Secretsregistry.AgentRegistryEntry.Networkregistry.AgentRegistryEntry.FilesystemAgentSpec.DependencyMap- existing secret provider chain
Instead, the first implementation should treat those current fields as
enforcement/runtime surfaces and introduce AgentNeeds and DependencyNeeds
as the user-facing declarative layer.
Later, the registry and launch code can be progressively aligned so those runtime fields are derived from effective needs rather than hand-maintained separately.
- Where should the needs catalogs live:
- agent registry YAML
- separate needs YAML
- catalog/metastore records
- How should dependency provider class names be resolved canonically across Go and Python?
- Should filesystem approvals be absolute paths only, or allow symbolic workspace aliases?
- Should capability approvals be stored per:
- user
- org
- guild
- agent class
- How should optional vs required needs be represented?
Adopt AgentNeeds and DependencyNeeds as separate, class-keyed requirement
catalogs and keep AgentSpec unchanged as the runtime launch object.
This gives Forge and Rustic UI a clean setup model:
- the UI can explain agent access clearly
- dependency-provider needs become explicit
- secrets and OAuth flows can be driven from the same model
- runtime launch stays decoupled from setup metadata
This is the right foundation for user-visible secret prompts, OAuth connect flows, and capability approval UX.