title: System Patterns tags: [patterns, architecture, design]
System Patterns
Recurring design patterns in the cowboy infrastructure. These are conventions the codebase follows, not separate subsystems.
Credentials live outside the agent
The agent never holds an API key. Instead of giving the agent a secret and trusting it not to leak it, secrets are held on the host side of a boundary the agent’s traffic must cross, and injected there.
Cowboy realizes this with the credential-injecting proxy
(proxy/addon.py, services.cowboy.secretsProxy): the agent makes an
unauthenticated request, and the proxy reads the secret from a file and writes
the credential header on the way out. The agent process can read neither the
secret file nor the proxy’s configuration. See
Security.
The general rule: if a capability needs a secret, put the secret behind a service the agent talks to, not in the agent’s environment.
Declarative over imperative
If state can be declared in Nix, declare it — don’t expose it as an agent tool. Prefer a reconciliation service that converges declared state over a tool that lets the agent drive an API directly.
- Declare desired state as structured Nix options.
- Generate a config artifact at build time.
- A systemd service reconciles declared state with the target.
Tools are reserved for inherently imperative operations: sending a message, running code, interactive queries. This is why bridges, filters, and the proxy are Nix modules that emit config and units rather than agent-callable tools.
Permission-separated, additive config
Split configuration by authority level so the agent can manage some of its own state without escalating privileges.
- A system layer is owned by the administrator and applied through the NixOS configuration.
- An agent layer is owned by the agent and applied through its home-manager configuration.
A reconciliation step merges the two additively, with the system layer winning on conflict: the agent can add, never subtract or shadow. A path unit watching the agent’s config file can trigger the system reconciliation service, bridging the unprivileged agent switch to a privileged service without granting the agent elevated access.
This is the same split that lets a plugin register skills/tools into an agent’s home while infrastructure stays under system control — see Plugin Architecture.
Capability through home, not core
A new capability is added by registering into the agent’s configuration —
skills, tools, packages on the agent’s PATH, pub/sub bridges — rather than by
modifying the harness. The harness reads per-agent config files
(~/.config/cowboy/{skills,tools}.json, the skills directory) at startup, so
most extensions are pure Nix with no Rust changes. The
plugin contract is the worked-out form of
this pattern.