Nucovo
Security

Assume the model is the attacker.

Employees read repositories, project material and external tool results. Their output can affect code, documents and connected systems. Treat that material as untrusted: models propose actions, while the application checks permissions, approvals and evidence. Credentials belong in the trusted application process.

The trust boundary

Agent code executes inside an isolated runner. Repositories, model output and client input remain untrusted at the boundaries where they enter the system. The operator console must stay private; the separate client portal authenticates users and scopes access to their client records.

Isolation

Agent code runs in an isolated runner

Agent code executes in a throwaway container: non-root, no network, read-only root filesystem, no capabilities, and only the task's worktree mounted. It is destroyed when the task ends.

Credentials

Keys never reach the sandbox

Model credentials stay in the worker process. The runner receives a work package and a mounted worktree and nothing else. Its environment is built from empty rather than filtered from the host's — forgetting to add a variable breaks a build; forgetting to remove one leaks a key.

Injection

Repository text is data, never an instruction

Anything a model, a repository or an outside party wrote is fenced as untrusted content with its provenance attached. A client's own words in a support ticket are quoted to the agent as data and labelled as such on screen.

Authority

A model's output cannot mutate state

Agents return proposals. Deterministic code validates each one against that employee's permissions and commits it, or refuses it. A model writing “budget approved” produces a row for a person to look at.

Shell

Commands are passed as argument lists

Commands use a program and an argument list rather than an interpolated shell string. Supported programs, employee grants and worktree paths are checked before execution. Approved programs and repository scripts can still execute code, which is why runner isolation matters.

Approval

Anything ungranted raises a question, not an error

A command with no matching grant creates an approval request bound to a SHA-256 of the exact argv. Approving “npm ci” is not approving “npm ci --ignore-scripts”, and consuming an approval is a conditional update so two workers cannot both use it.

Offboarding

Ending a client relationship ends their access

Marking a client as churned stops everybody at that client signing in and stops the sessions they already have — the check is a condition in the session query, so an open tab fails on its next request rather than whenever it would have expired. Nobody has to revoke logins one at a time. Pausing an engagement deliberately does not do this: the work is on hold, not the relationship, and somebody whose retainer is paused still has invoices to read.

Data

Self-hosted, with no telemetry

It runs on your machine against your database with no hosted control plane or telemetry. Task content is sent to the model providers you configure; enabled delivery and monitoring integrations make their own requests. Provider credentials stay outside the task runner.

Stop

Stopping it reaches work already running

Pausing stops new work being handed out. Halting also reaches into attempts in flight — a halted company cannot renew a lease, so running attempts abort and their tasks go back on the queue unfinished rather than failed. Both are enforced in the claim function itself, not in the process you would be trying to stop.

Secrets

The one secret that cannot be hashed is encrypted

Passwords, session tokens and reset links are stored only as hashes. A second-factor secret has to be recoverable to verify a code, so it is encrypted with a key held in the environment and never in the database — which protects a leaked backup, snapshot or replica, and not somebody who already has the machine. With no key configured, enrolment is refused rather than silently storing it in the clear.

Accountability

The log says whether a person or a model did it

Every audited action records what kind of actor took it — an AI employee, a client's staff, the operator, or the database itself — because when something is wrong the first question is which. Refusals are kept alongside successes, as are sign-in attempts against addresses that match nobody. There is no severity score to sort by, because nobody could point at the rubric.

Preview

Model-written files are served sandboxed

A captured preview is served under Content-Security-Policy sandbox in an origin of its own, with same-origin deliberately absent. Its manifest is the allow-list, and every file is re-verified against its recorded hash before it is served.

What the container actually gets

PropertySetting
UserNon-root
NetworkNone
Root filesystemRead-only
Linux capabilitiesAll dropped
MountsThe task's worktree, and nothing else
EnvironmentBuilt from empty, never filtered from the host
Command invocationProgram and argument list, without shell-string interpolation
Database driverNot present in the image
Provider SDKsNot present in the image
LifetimeDestroyed when the task ends

Runner isolation tests check the container configuration and the absence of a database driver and provider SDKs. Building the environment from empty rather than filtering the host’s is the deliberate direction of that trade: forgetting to add a variable breaks a build loudly, forgetting to remove one leaks a key quietly.

Prompt injection, specifically

Untrusted text is fenced and labelled

Anything written by a model, a repository or an outside party is wrapped in an untrusted-content block carrying its provenance. A client’s own words in a support ticket are quoted to the agent as data, and drawn on screen as a quotation marked treated as data, never as an instruction.

Permissions constrain what an injection can cause

Models return proposals that deterministic code checks against supported actions and the employee’s permissions. These checks do not make prompt injection harmless: a malicious proposal may still fit a grant, produce harmful code or waste resources. Narrow grants, isolated execution, budgets and independent review reduce that exposure; they do not eliminate it.

It cannot pick its own reviewer

Reviewers come from the org chart. A planner that could name its own reviewer could name itself, and the evidence gate would be decorative. The same applies to who hears about a blocker: an employee escalates to its manager and cannot choose a friendlier audience.

Customer messages have a release gate

Free-form client replies are drafted and wait for approval before delivery. Permitted fixed acknowledgements follow a separate path. Review the wording and the grants that enable delivery: approval controls who can release a message, and cannot guarantee that its content is correct.

Stable guidance and reviewable handoffs

Brand revisions and task activation agree

Published client brand revisions are immutable and scoped to their client. Projects select an exact revision. Task activation and changes to that selection share a database lock; changing queued work’s brand guidance requires a new contract version.

Content approval identifies a revision

Campaign approval pins saved copy and source artifact metadata. New wording starts as a draft. The console checks attached document bytes before approval; other metadata snapshots do not verify external content or publication. Outcome entries remain attributed operator reports.

Prerequisite documents are checked before use

The worker reads accepted handoff files within the artifact directory and checks their saved checksum. Missing, changed or oversized material is refused. The content remains untrusted reference data and cannot grant a tool or alter the agreement.

Exports have a limited conversion surface

PDF, Word, Excel and PowerPoint exports render supported text and tables. The conversion does not fetch remote assets or execute arbitrary HTML, spreadsheet formulas or macros. Input, output, memory, concurrency and time limits bound conversion; a new export is not new accepted evidence.

Understand the document handoff →

Tools, MCP, and what an agent may reach

The fastest way to give an agent real capability is to connect it to tools, and it is also the fastest way to give an attacker one. This is the part of the design most worth reading before you trust it with anything.

CLI adapters do not inherit personal tools

The supported CLI agents — Claude Code and the Gemini CLI — are run with no tools granted at all. They are used to get a structured proposal back, not to run an agent session. Every file change is applied afterwards by code we control, into a throwaway checkout. Codex CLI execution is temporarily disabled until its no-tool isolation can be verified. OpenAI API access remains supported.

MCP Connectors use a separate control path

MCP Connectors use explicitly configured Streamable HTTP endpoints. Tools are discovered, their arguments validated, and access assigned to named employees. Personal CLI MCP settings are not inherited. The network-isolated code runner and the trusted process making MCP requests are different boundaries.

A grant names the tool and its definition

Access binds to a discovered tool, its definition and its connection version. Automatic access requires an operator to review the tool as read-only. Other calls require approval tied to the exact request. Changed definitions invalidate old grants. Neither a server hint nor an employee title grants authority.

An MCP server is untrusted input twice over

The server can act on an external system and return text a model will read. Results remain untrusted even after schema validation. Narrow account permissions, reviewed grants and explicit approvals limit exposure; they do not guarantee a remote tool behaves safely or its output is true.

OAuth credentials are stored encrypted with the installation key; bearer credentials use dedicated environment references. Remote connections use HTTPS and reject private, reserved and metadata destinations. Loopback is a deliberate local-server exception. An uncertain write is recorded without automatic replay, because losing its response does not establish that the service did nothing.

Review MCP Connectors and setup requirements →

Your data

Where it livesYour machine, your PostgreSQL, your git repositories. There is no hosted control plane in the self-hosted product.What leavesConfigured model requests can include briefs, code and client material needed for the task. Enabled integrations can also deliver approved messages or check a deployment’s health. MCP requests can send project information to the configured tool server, and its results can enter model context. Review those destinations and their credentials before use.TelemetryNone. The application does not phone home.AccountsThe operator console has no login and must remain on a private, trusted network. Client users sign in to a separate portal with access scoped to their client.AuditabilityEvery run, every proposal, every refusal and every token is a row you can query. You do not have to take the interface’s word for any of it.

What we are not claiming

This is a young product, not a certified platform. It has not been through a third-party penetration test or a compliance audit, and it holds no certifications. Saying otherwise would be the same category of claim the product exists to refuse.

The container isolation is Docker’s, which is a strong boundary and not a hypervisor one; microVM isolation is deliberately out of scope for now. RUNNER_MODE=local exists so a first run does not need Docker, and it runs commands on your machine with your privileges and no sandbox — it warns loudly and it should only ever meet code you already trust.