How Praxis works and stays safe

How the Praxis agent runs your infrastructure work server-side, what it can read freely versus change, and where its security boundaries genuinely sit.

Praxis is Facets' agentic layer: AI that reads your infrastructure, explains it, and proposes changes through conversation. This page covers what actually runs when you talk to Praxis, how it acts on your behalf, and what keeps it safe to point at production systems.


What Praxis is under the hood

Praxis is mostly one general agent, not a fleet of separate products. When you chat with it, a single DevOps agent loads skills on demand: each skill is a written procedure for one job, such as importing a resource or auditing a blueprint (a Facets environment configuration). Skills ship built-in, and you can add your own. The agent pulls in only the skills a task needs rather than carrying all of them at once. A few specialist agents sit alongside it for focused work and to power the apps.

Three related ideas are easy to confuse, so it helps to name them:

  • A capability is a skill: a procedure an agent loads when it needs it.
  • An agent is a configured persona that you chat with or delegate to, built from a system prompt, a model, and a chosen set of capabilities. Some are built-in, and you can build your own.
  • An app is a packaged product surface with its own screens, its own data, and a per-organization on/off switch. Four apps ship today, listed under Agentic Apps.

How you reach Praxis

You work with Praxis in three places, all backed by the same agent under the same permissions:

  • The web console, where you ask Praxis in a chat session and watch it work.
  • The Praxis CLI, which drives the same agent from your terminal, your AI tools, and your CI pipelines.
  • Slack, once your organization connects a workspace: @-mention an agent in a channel, or have it watch a channel and respond on its own.

Whichever surface you use, the agent runs server-side under your organization's credentials and follows the same access rules below.


Where it runs

Praxis runs server-side, in a managed cloud environment, never on your laptop. When a task needs a command-line tool for the cloud, for Kubernetes, or for the Facets Control Plane, that tool runs on the server under credentials your organization has already stored. The model composes the command as text; it never receives the credential itself.

When you drive Praxis programmatically, from the CLI, your AI tools, or CI, each tool call travels through the MCP gateway. (MCP is the connection layer that lets an agent use an external tool.) The gateway is where identity and auditing are enforced:

  1. A request arrives carrying an API key.
  2. The gateway resolves your organization and user from that key. It never trusts an organization or user identity sent by the caller.
  3. It runs the requested tool server-side, under your organization's stored credentials.
  4. It writes an audit row for the call: who ran it, which tool and function, the result, and how long it took.

The chat console, Slack, and scheduled runs invoke the same tools in-process rather than over the gateway, but they enforce the same access rules, the same organization scoping, and the same per-command logging. Under heavier orchestration a main worker splits a job across additional worker processes, and this identity and audit path is the same for all of them.


What Praxis can read and what it can change

Praxis reads infrastructure freely and is deliberately limited in what it can change. How that limit is enforced depends on the system it is touching, so it is worth being specific rather than saying "read-only" and stopping there.

Cloud and Kubernetes access is genuinely read-only. Praxis reaches AWS, GCP, Azure, Kubernetes, and Helm through built-in tools that inspect each command before running it. Read verbs such as list, describe, and get run; anything that would change state, such as create, delete, update, apply, or scale, is refused inside the tool before any command executes. This holds on every surface and in every mode, whether or not a person is watching. Shell pipes and redirection are rejected by the same check, so a read command cannot smuggle in a write.

Facets changes go through raptor and are gated by your Control Plane's own access control. When Praxis changes Facets infrastructure, creating a release, applying a resource, setting a variable, or deleting a release, it runs raptor, the Facets Control Plane CLI. Raptor is not filtered to read-only operations. Instead, every command it runs is checked server-side by the Facets Control Plane's role-based access control, against your resolved Facets personal access token (PAT). What Praxis can change is exactly what your PAT is permitted to change, and no more. For what raptor is and how it differs from the Praxis CLI, see Praxis CLI.

Writing files and running other shell commands waits for approval. Editing files and running shell commands that are not on the built-in read-only list are not auto-approved. In an interactive session you steer this with slash commands typed into chat:

  • /mode sets how actions are approved: review each one, review a plan once, or accept all automatically.
  • /ask poses a question that runs no tools, and /model switches the model.
  • /compact, /clear, and /rewind condense, reset, or step back through the conversation.

Reviewing each action needs a live connection. If yours drops before you answer a prompt, the pending action is denied rather than assumed.


What happens in an unattended run

When Praxis runs with no person present, watching a Slack channel, running on a schedule, investigating an incident, or driven from CI, there is no approval prompt for anyone to answer, so tool calls are auto-approved. Safety in these runs does not come from a human approving each change. It comes from the boundaries that hold with no one in the loop:

  • Cloud and Kubernetes stay read-only, enforced inside the tools.
  • Facets changes stay within whatever the run's PAT is allowed to do under Control Plane RBAC.
  • Credentials never reach the model, and the deny list and environment scrubbing below still apply.
  • Every run is attributable to a real identity and every command is logged.

An agent can still choose to pause and ask a question mid-run. In Slack that becomes an interactive prompt the run waits on before continuing.

These boundaries are the shared foundation for every Praxis capability and app. Each one applies them to its own surface and states any limit specific to it.


Credentials and tenant scoping

Stored credentials are encrypted at rest with Fernet (AES-128-CBC with an HMAC-SHA256 integrity check) and are never shown back to you or to the model. When a command needs a secret, you reference it as ${credential:name}. The value is substituted server-side just before the command runs, so the secret never enters the model's context.

Every record Praxis reads or writes is scoped to its owner and organization, so one organization's data cannot surface in another's session. An API key inherits the permissions of the person who created it; there are no separate per-key scopes. Your Facets PAT is resolved per command and passed only to the raptor process that needs it, never placed on the agent's own environment and never shown to the model.


Honest limits

The separation described above is defense-in-depth, not kernel-grade isolation, and it is worth being precise about what that means.

📘

Praxis does not run each user or each run in its own operating-system sandbox. A single shared container runs as a non-root user, and separation comes from several layers working together rather than from a hard operating-system boundary.

Those layers are:

  • working-directory separation between runs,
  • owner-and-organization scoping on every query,
  • a deny list that blocks the agent from reading or editing its own permission settings and the workspace kubeconfig, and from running shell commands that dump the environment (env, printenv, set) or invoke raptor directly, and
  • removal of sensitive environment variables, including the model's own API key, before any shell command runs.

Be precise about what the deny list is: a targeted barrier, not a blanket filesystem lock. It raises the bar against casual credential exfiltration rather than making it impossible.

One more limit is worth stating plainly: there is no global filter that strips secrets from logs. Some tokens are redacted where they are specifically handled, but the gateway's audit records store call arguments as they were passed, unless a tool declares a field to mask. Treat anything you pass to a tool as something that can appear in an audit record.


  • Praxis CLI - Drive Praxis from your terminal and CI, and how it differs from raptor
  • Build your own agent - Configure a custom agent's persona, model, and capabilities
  • Agentic Apps - The packaged apps and how they build on this shared model
  • API Reference - Programmatic access through the MCP gateway