There is a shortcut in AI tooling that looks convenient at first.
We connect a tool, an MCP server, a GitHub integration, a local command runner, or a task tracker. After that, the interface starts to suggest that the agent now "can" work with repositories, tasks, pull requests, files, and commands.
But for a serious team, that is not enough.
Technical ability is not the same as permission. And even an allowed action may still need a human decision.
That is why NexFlow separates these things.
For context, NexFlow is an open specification-first project for describing AI developer teams before running them: agents, capabilities, permissions, context, memory, handoffs, and human approval gates.
A capability answers one question: what can an actor or integration technically do?
A permission answers another question: is a specific subject allowed to use that capability?
An approval gate adds a third layer: does the action require explicit approval before it happens?
This may look like a small distinction. In practice, it decides whether an AI-assisted workflow can be reviewed, or whether it depends on the hope that "the agent will understand."
Skill, capability, permission
It is better to start with the vocabulary, because this is where the confusion usually begins.
A skill describes role suitability. For example: schema_review, backend_review, or documentation_writing. It says that an actor is suitable for a type of work.
A capability describes the action surface. For example: read_repository, write_repository, create_pull_request, execute_command, read_context, modify_documentation, or deploy_application.
A permission describes a policy decision: allowed, denied, or allowed only after approval.
An approval gate describes who or what must approve a gated action.
In one sentence: an agent may have the skill for code review, an integration may expose the capability create_pull_request, but a permission still has to say whether this agent may create a pull request, and an approval gate may require human review before the action.
This matters in NexFlow because agents, humans, automation systems, and integrations are part of the same team description. A connected tool should not automatically authorize every actor.
Capability makes the risk surface visible
A capability does not allow anything by itself.
But it makes risk visible.
A simplified capability example:
specVersion: "0.1"
kind: CapabilitySet
capabilities:
- id: create_pull_request
description: Open or update a pull request in a declared repository.
risk: medium
category: source_control
requiresApprovalByDefault: true
auditRecommended: true
This record does not say that an agent may open a pull request.
It says that the project contains an action with a specific risk profile. A reviewer can see this action surface before any runtime tries to execute it.
For high-risk actions, this is especially important:
specVersion: "0.1"
kind: CapabilitySet
capabilities:
- id: execute_command
description: Run approved local commands such as tests or linters.
risk: high
category: runtime
requiresApprovalByDefault: true
auditRecommended: true
execute_command looks familiar in a developer workflow. But it is one of those capabilities that can easily become too broad. Running tests is one thing. Installing a dependency, changing the environment, or executing a destructive command is another.
A capability vocabulary keeps that risk from being hidden inside prompts or UI assumptions.
Permission makes the decision
A permission connects a subject to a capability.
In the draft NexFlow model, there are three practical effects:
allow
deny
approval_required
For example, a docs agent may read a repository without separate approval:
specVersion: "0.1"
kind: PermissionSet
permissions:
- id: docs_repository_read
subjects:
- docs-agent
capabilities:
- read_repository
effect: allow
But the same docs agent may also be explicitly restricted:
specVersion: "0.1"
kind: PermissionSet
permissions:
- id: docs_agent_no_deploy
subjects:
- docs-agent
capabilities:
- deploy_application
effect: deny
That rule is useful even before there is a runtime.
It makes policy reviewable. A person reading the manifests can see not only the role of the agent, but also the boundaries of its actions.
For actions that are allowed only after review, the effect is approval_required:
specVersion: "0.1"
kind: PermissionSet
permissions:
- id: implementation_write_with_review
subjects:
- implementation-agent
capabilities:
- write_repository
- create_pull_request
effect: approval_required
approvalGate: code_review
This is not a UI button.
It is a policy boundary.
An actor may be technically able to prepare a change. But the record says that a declared gate is required before a write action or pull request creation.
Integration capability is not actor permission
The most common mistake is to move a capability from an integration to an actor.
For example, a GitHub integration or MCP server may declare that it requires a capability:
requiredCapabilities:
- create_pull_request
That only means the integration has an action surface related to pull requests.
It does not mean that every agent that can see this integration may create pull requests.
The actor still has to be authorized through permissions. If there is no permission, a future runtime should reject the action. If the permission has the effect approval_required, the action should wait for a gate. If there is an explicit deny, a gate should not turn a denied action into an allowed action.
This boundary protects a project from a strange failure mode: "we connected the tool, so the agent received more authority than we thought."
Deny should be conservative
The NexFlow security model proposes conservative permission evaluation.
The practical order is:
- Confirm that the actor has the requested capability declared.
- Find applicable permission rules.
- Treat explicit deny as strongest.
- Treat approval_required as blocked until approval is satisfied.
- Treat allow as valid only inside the declared scope.
- Reject the action if no applicable permission exists.
This is not bureaucracy.
It protects the project from broad allow rules.
For example, an implementation agent may be generally allowed to work with a repository. But deployment may be denied separately. If a broad allow wins, the safety rule becomes decoration. If explicit deny wins, project policy stays predictable.
An approval gate should not bypass deny either.
If an actor is denied deploy_application, an approval request should not make deployment acceptable. The permission policy has to change; the team should not rely on an approve button to override a denial.
What an approval gate is
An approval gate describes a decision point.
A simplified example:
approvalGates:
- id: code_review
description: Reviewer approval required before repository writes or pull request creation.
requiredApprovers:
- reviewer
appliesTo:
- write_repository
- create_pull_request
events:
- review.requested
- review.completed
A good approval gate should be scoped.
Approval for one pull request should not automatically allow deployment. Approval for one command should not become permanent permission to run commands. Approval for a task memory write should not allow an organization memory update.
In future runtime semantics, approval should carry evidence: who requested it, what is changing, which files or artifacts are affected, what the risk summary says, and which tests or validation outputs exist.
NexFlow does not implement enforcement today.
But the specification vocabulary already makes it possible to describe where human authority should be visible.
Why this is useful before runtime
One question is fair: why write all of this if a runtime does not execute the manifests yet?
Because review starts before execution.
A team can read the manifests and see:
- which risky capabilities exist at all;
- which actors may read the repository;
- who may write files;
- where approval is required;
- which actions are explicitly denied;
- where an extension requires capabilities but does not grant authority by itself.
That is already better than discovering permissions through scattered prompts, local settings, and team memory.
NexFlow is still a specification-first project. The repository contains draft documentation, schemas, examples, and RFCs. Runtime enforcement, provider integrations, and a reference CLI are all future work.
But capability, permission, and approval gate are already useful as a language for review.
Because in an AI developer team, what an agent can do is not enough.
What matters is what the project says the agent may do.
And where a human must stop the action before it becomes a side effect.
Top comments (0)