Web app
Projects
Each agent is a project: its guardrails, its traffic, what it may do and what it changed from the workspace's settings, on one set of pages. The API still calls a project an agent (/api/agents).
In the web app Projects
When to use this
- To see and change what protects one agent, where it acts.
- To add projects a scan proposed, and find agents nobody registered or owns.
- To switch a feature on or off for one project without changing the others.
- To stop an agent now.
All projects, or one
The switcher at the top of the sidebar picks the scope. All projects is the workspace: Home, Projects, Observe, Issues, Policies, Features, Approvals, Test and Reports. A project shows only its own pages: Canvas, Activity, Access, Features, Issues, Approvals and Settings. Issues and Approvals are the workspace pages filtered to the project (?agent=<slug>). Opening a project's link switches to it; the choice is remembered.
The projects list
/app/projects, built from GET /api/agents: every project with its owner, risk, requests and how many were stopped, open issues and last activity. Needs attention lists unregistered and unowned ones; Proposed lists the drafts a repository scan found, with Add project (POST /api/agents/{id}/approve) and Dismiss. A draft is inert until it is added. A multi-agent system (OpenAI Agents SDK, LangGraph, CrewAI, AutoGen, Google ADK) is proposed as one project per agent, each with its own tools, listed under the agent that hands it work; Add all adds the whole system (POST /api/agents/{id}/approve-system). The hand-offs its code declares show on each project's canvas before any traffic.
Creating a project by hand
New project is for an agent that does not live in a repository you can connect: an ID (unique, lowercase), name, purpose, owner and risk level, posted to POST /api/agents. An agent that calls the gateway before anyone registers it shows up as unregistered; creating the same ID claims it.
agentfox agents listThe canvas
In the web app Projects → a project
A project opens on its canvas: its guardrails drawn where they act. The user's message, the agent, its reply, documents and memory, tool calls, the tools, and what tools return. Each step is coloured by what applies there: enforcing, watching only, or nothing set. Agents it hands work to are drawn beside it and open their own project. Built from GET /api/agents/{slug}/map.
- Many tools are one Tools node until you choose Expand. Then they are drawn as groups (by risk, access, source or server), at most six, and an opened group shows at most six of its tools. A +N more node opens the full, searchable list in the inspector.
- The inspector on the right shows what is selected: a step's rules and checks, or a tool's access, rules and limits, each changeable for this project there. With nothing selected it shows the project: its requests, blocked, held and errors, its open issues, the guardrails that fired most, its lineage (the blast radius, and Open lineage map for everything within two hops), who owns it, its tools and the rules that apply at every step.
Activity has the project's requests over the chosen range against the range before it (a window in the chart opens its runs), its runs, the guardrails that fired, and answer quality. Access is its tool permissions and limits and the knowledge boundary below. Settings has its owner and registration, the circuit breaker and the kill switch.
Features
In the web app Features
The switches a developer reaches for, set once for every project on /app/features and changed per project on its own Features view.
- Protections: prompt attacks, personal data, secrets, harmful content, off-task actions, unsupported answers and insecure code, each off or at a sensitivity (low, medium, high), or off and on. Each shows whether it is blocking or only watching.
- Checks: the detectors that run on traffic, on or off. A check that is not installed in this deployment cannot be switched on.
A project starts with the workspace's value for every switch and says so ("Inherited from the workspace"). Changing one marks it changed here; Reset goes back, and so does setting it to the workspace's value. A later change for every project reaches every project that inherits it.
- A project can always be stricter than the workspace.
- It can be lower (less sensitive, or off) only where the workspace ticked Projects may lower for that protection, which needs a role that may enforce policies. Until then the lower levels are shown locked, with the reason. Protections that keep the others from being switched off are never lowered per project.
- A check can be switched either way per project, except the always-on safety net. The gateway applies the project's choice on every call, not only on the screen.
GET /api/features
GET /api/agents/{slug}/features
POST /api/features/protections/{key} {"level": "high", "agent": "support-triage"}
POST /api/features/checks/{key} {"enabled": false, "agent": "support-triage"}Every change is an operator action in the audit log. Under the hood a protection is a set of rules in a shipped pack; a project's change is a copy in its own layer (see Policies).
The setup banner
Until setup is done, a line at the top of each page says what to do next, sized to the one missing step. In a project, in order: add it (it was proposed by a scan); send its first request (with a test request that names it, and the banner clears itself when that request arrives); allow the tools it should use; and turn blocking on, after seeing how many of last week's requests it would have stopped. With all projects in view it is about the workspace: connect the first agent, then the first request, then the next step on Get started. Built from GET /api/onboarding and GET /api/agents/{slug}/setup. Hiding it keeps it hidden for a week.
Knowledge boundary
On the Access view. A knowledge boundary is what the agent may answer from; without one, nothing stops it inventing an answer to a question it has no data for. Fields:
- Systems of record it may answer from (comma-separated)
- Coverage (months of history) and Freshness (hours)
- Entity types it knows about (comma-separated)
- Topics it must refuse even if it has data (comma-separated)
- Question types it may answer: fact, aggregate, prediction, opinion, procedure
Declare boundary (or Update boundary) sends PUT /api/answerability/boundary. The form has no mode field: a boundary saved from the web app is in observe, so refusals are recorded, not applied. Enforce it from the CLI once the dry runs look right.
agentfox declare boundary research-bot --systems wiki,ticket-history --coverage-months 12 --answerable fact,procedure --out-of-scope "legal advice,medical diagnosis"
agentfox test boundary research-bot "Can you give me legal advice about this contract?"✓ boundary declared for research-bot
answerable: fact, procedure
coverage: last 12 months
observe mode — refusals are recorded, not applied. Re-run with --mode enforce when the dry runs
look right.
╭─ would abstain — out_of_domain ───────────────────────────────────────────────╮
│ That topic is outside what this agent is set up to cover (legal advice). │
╰───────────────────────────────────────────────────────────────────────────────╯
recorded only (observe mode)Kill switch, quarantine and resume
The current state is shown as a tag: active, quarantined or killed. Any state other than active refuses every governed call from the agent immediately, and each change goes to the audit chain.
- Quarantine (with an optional reason) is the reversible "stop while I investigate". Allowed for owner, admin, security and developer.
- Kill is the incident action, with no reason field in the web app. It needs owner, admin or security.
- Resume (optional reason) returns the agent to active. It needs the same roles as Kill: restarting something stopped for cause is not a lesser decision.
The form posts to the web app's /api/agents/<slug>/control, which calls POST /api/agents/{slug}/quarantine, /kill or /resume. The CLI does the same:
agentfox agents quarantine research-bot --reason "checking an odd tool call"
agentfox agents resume research-bot --reason "incident closed"research-bot killed → active incident closed(That resume followed a kill made in the web app.)
Owners and shadow agents
An agent with no owner shows unowned — assign on the list and an unowned tag; assign one on its Settings view. An unregistered agent is one the gateway saw in traffic under a slug nobody registered. It raises a high-severity attention item ("'slug' is running and was never registered") and a finding. Register it with the same slug, give it an owner, then resolve the finding.
Common tasks
| You want to | Run |
|---|---|
| List projects, owners and shadow agents | agentfox agents list |
| See what one agent reached | agentfox agents lineage payments-ops |
| Stop an agent while you investigate | agentfox agents quarantine research-bot --reason "…" |
| Stop an agent now | agentfox agents kill research-bot --reason "…" |
| Bring it back | agentfox agents resume research-bot --reason "…" |
| Show the policy in force for it | agentfox policy effective --agent payments-ops |
| Declare what it may answer, in enforce | agentfox declare boundary research-bot --systems wiki --mode enforce |
| Let it call a tool | agentfox permit grant research-bot web.fetch --yes |
What can go wrong
- Kill or Resume shows an error banner. Your role is developer; those need owner, admin or security. Quarantine is still available to you.
- "no draft agent with that id" on Approve or Reject. Someone already decided it; reload.
- Tools count is high but nothing is allowed. Tools are declared; grants are separate and default deny. Allow them on Access, or see Contain tool calls.
- A lower level is locked on a project's Features. The workspace has not let projects lower that protection. Tick Projects may lower for it on the workspace's Features, or change it for every project.
Limits
- Boundaries saved from the web app are always observe mode.
- The risk classification is a heuristic over purpose text and behaviour, not a legal determination.