Back Curiosity Studio

Curiosity Studio

Sudo

The admin assistant of Curiosity Studio. He works the way a developer works — reads files, runs commands, hands you a diff — and nothing he writes reaches the workspace until you approve it.

Despite the name, he never assumes elevated privileges. He reads the graph as the administrator talking to him, and he asks first.

The problem

A workspace has a lot of surfaces

Endpoints, AI tools, agents, skills, prompt templates, scheduled tasks, migrations, connectors, indexes, node schemas, node renderers, NLP pipelines, chat policies, search settings. Every one of them has an admin page, and every one of them is a different page.

The surface keeps growing
A product that grows a new kind of configuration grows a new screen to configure it on, and an assistant driving per-surface tools grows a new tool to match.
The work spans surfaces
"Let users filter tickets by product" is a schema field, an index setting, a facet and possibly a migration. Four screens, in an order you have to know.
Changes are unreviewable
A configuration edited screen by screen has no diff. What changed is whatever you remember changing.
The answer is one layer down
All of it already round-trips through the definitions export as plain files — the export zip, the WebDAV mount, the git-tracked configuration.

The idea

Hand him the configuration as a filesystem

There is one tool, one sandbox, and one way into the workspace.

Your configuration is already files, so Sudo changes it the way anyone changes files: cat and grep to read, sed or a heredoc to edit, build to compile, commit to hand it over.

A new kind of surface needs no new tool. A new export folder is a new folder.

The filesystem

Nine mounts, two of them writable

/
├── workspace/       the configuration, exactly as the definitions export writes it   [writable]
├── reference/       a generated example workspace, one well-formed file per surface  [read-only]
├── docs/            one page per code-execution scope, plus the schema helper        [read-only]
├── sdk/             the C# surface your workspace code is written against            [read-only]
├── proc/            live runtime state, regenerated on every read                    [read-only]
├── session/         his own to-do list                                               [read-only]
├── stage/           the files you uploaded to the Stage area, as text                [read-only]
├── home/uploads/    the files you attached to this conversation                       [read-only]
└── tmp/             scratch, discarded with the session                              [writable]

Only a write under /workspace is a change to your workspace. That is what makes diff and commit answerable by comparing one directory against the live configuration.

The filesystem

What is in each one

Reading the workspace

  • /workspacecode/endpoints/, code/agents/, config/schemas/nodes/, nlp/… one file per thing you configure by hand.
  • /reference — a well-formed example of every file kind, regenerated with the product, so he reads the shape rather than recalling it.
  • /docs — what each code-execution scope exposes.
  • /sdk — signatures and documentation, bodies rendered as { ... }.

Reading the running system

  • /proc/nodetypes, /proc/edgetypes — types with counts (TSV).
  • /proc/exceptions — the 100 most recent (JSON).
  • /proc/audit — who changed what, and when.
  • /proc/scheduled-tasks, /proc/connectors, /proc/indexes, /proc/metrics, /proc/logs.
  • /proc/runs/<id>/status, log, output for anything this session started.

/proc regenerates on every read, so the same cat a minute later shows how far a still-running task has got, and jq works on it directly.

The sandbox

One tool: a shell that never leaves the process

The interpreter is Computerwelt, an open-source .NET library providing an in-process bash and an in-process Python over one virtual filesystem. Both are managed C# implementations of the language.

No bash binary
There is no PATH lookup. A command is either one the sandbox implements or a "command not found".
No CPython
python cannot import a native module or reach the host. Monty implements json, re, math, datetime, collections, os, pathlib, io, glob, dataclasses and a few more.
No process at all
Nothing is forked, nothing is executed, no container is started.
Everything else works
ls, cat, grep, rg, find, sed, awk, cut, sort, uniq, wc, diff, jq, yq, xargs, pipes, redirection, heredocs, subshells, functions, loops, variables, arithmetic.

A configuration assistant that shells out to a real shell has the host's authority. One that interprets the script itself has only what its host handed it.

The sandbox

Absent, not blocked

What is missing by construction

  • No host filesystem. All I/O goes through the virtual filesystem. No path resolves to a file on the server.
  • No process spawning. No fork, no exec, no PATH.
  • No network. curl, wget, nc, ssh, git and the rest are withheld rather than present and refusing — so the day the library grows one, the session does not silently acquire it.
  • No writes outside /workspace and /tmp.

Enforced limits

Limit Value
Wall clock per script 120 s
Commands per script 100,000
Output captured 4 MB
Idle session lifetime 30 min

A cap that is reached raises rather than returning a partial answer, so a traversal that stopped half way is never reported as the whole.

Workspace code can still call out once it has been approved and is running. That is the code's authority, not the assistant's, and it only exists after you approved it.

The sandbox

One session per chat

A session is keyed by the conversation it belongs to. Two administrators in two chats never share a working directory, an uncommitted edit or a to-do list.

What persists
Only what the session changed — the files it wrote, the paths it deleted, the working directory, the command history, the to-do list. A session that only ever read leaves nothing behind.
What does not
Everything else is re-read from the live workspace on every command. An endpoint someone else edited in the admin pages meanwhile is the one Sudo sees on his next command.
Which is not a snapshot
Resuming means finding the file where he left it, in a workspace that has moved on — not restoring the workspace as it was.

The commands

What the sandbox adds on top of bash

A small set of commands for what a text editor and grep cannot do.

Reading

  • graph types · graph stats <type> · graph sample <type>
  • graph get <uid> [--edges] · graph edges · graph history
  • graph search <text> — as the chatting admin would see it
  • query — read-only, under the admin's own permissions
  • type <name> — the generated helper for one type

Changing and operating

  • status · diff — what this session has touched
  • build — parse and compile every changed file
  • commit -m "why" — stage the change set and stop
  • run task / run migration / run reindex
  • uid endpoint /api/… — mint a stable UID
  • tasks — his own plan, rendered to /session/todo.md

graph and query are read-only, run under the chatting administrator's permissions, and skip node types that are never returned to clients.

The loop

Read, edit, build, commit, approve

The interface

Where the conversation happens

The admin chat pane is collapsed by default and opens from a floating toggle carrying his avatar. Its expand button opens the same conversation full-screen, with room to read a diff.

The open session is kept in the address, so a refresh, a bookmark, or a link sent to another administrator comes back to that session rather than to whichever one the page was opened on.

The interface

The full-screen assistant

The interface

The pane knows what you are looking at

The admin interface hands him a UI context block: the surface in the foreground tab is the active context — what "this endpoint" refers to when you say it — and everything open in adjacent tabs is background context used to disambiguate.

The pending-changes panel
The commit he has staged, if any, and the button that opens it for review.
The terminal window
The same shell he is working in, opened from the chat toolbar, for when you would rather look yourself. Tab completion offers his uncommitted files.
The built-in editors
He perches on the modal of a built-in AI tool, agent, skill or prompt template, which is how you tell a built-in from something your workspace authored.
The attach button
Uploads a file into the conversation; he reads it at /home/uploads/<name>. A PDF or spreadsheet reads as extracted text, a .zip as a directory he can walk.

Approval

commit stages a change set and stops

What you approve is the diff you were shown.

Build before commit
commit parses every changed file back through the workspace's own importer and compiles its body against the scope it will run in — and against the workspace as the whole change set leaves it. It refuses the whole set if anything fails. --force exists, says so loudly, and still needs your approval.
One way in
An approved commit is an ordinary definitions import of the files that differ, routed by exactly the same code that reads an uploaded definitions bundle. There is no parallel set of per-surface writers that could drift out of step with it.
One tracked change per approval
The import runs inside the workspace's tracked configuration change, so an approved commit is one commit in the configuration git history, attributed to the administrator who approved it.

Approval

Reviewing a change

Approval

Two shapes, three buttons

How the diff is presented

  • File list — the changed files with a side-by-side diff for the one you select. Best for checking one file closely.
  • Pull request — every file's diff one after the other down one page, with a comment box under each. Best for a change that spans several files.

The diff is read-only on purpose: editing his draft in the review screen would leave the file in his shell disagreeing with what was applied.

What the buttons do

  • Approve — applies every file, streaming its progress on the server. Closing the tab costs you the log, not the change.
  • Discard — throws the commit away and keeps the edits. Tell him what to change.
  • Reset — throws away every uncommitted edit, putting his shell back to the live configuration.

A card left open while he staged a newer commit refuses to apply: the id you were shown and the id he is holding differ, so approving would apply something nobody read.

Approval

What approving actually does

Deletions first
A change set that removes an endpoint and adds one on the same route removes before it adds, rather than deleting what it just created. Search-index halves and package declarations are handled together, because they only mean something as a pair.
Then each file
Imported through the definitions importer, with the importer's own warnings reported as they happen.
On success
One tracked git commit attributed to you, and his session reloads from the live configuration so his next command reads what was actually applied.
On partial failure
The errors are reported and the edits are kept. Whatever did not import is still work someone did.

Approving says so in the conversation, in your voice, carrying any notes you typed while reviewing. Discarding says nothing — so silence is not approval.

Prompts · asking

Questions change nothing

About the configuration

  • "Which endpoints are reachable without authentication?"grep -l over /workspace/code/endpoints/ for the public access mode, then each match's header for the route.
  • "What does the support-triage agent do, and which tools can it call?"cat /workspace/code/agents/support-triage.cs; the whole agent is one file.
  • "Which node types have no search index?"/proc/nodetypes against /proc/indexes, joined with awk.

About what is running

  • "How many Ticket nodes are there, and what does one look like?"graph stats Ticket and graph sample Ticket -n 3.
  • "Are any scheduled tasks failing?"/proc/scheduled-tasks for the outcome, /proc/exceptions for the errors behind it.
  • "Something broke after the last deploy. What is throwing?"/proc/exceptions by type, then /proc/audit for what changed around that time.

Prompts · building

Each change ends in a diff

New surfaces

  • "Add an endpoint that returns open tickets grouped by product." — reads /reference for the file shape and /docs for the scope, mints a UID with uid endpoint /api/…, builds until it compiles, commits.
  • "Give the assistant a tool that looks up a customer's open cases." — a file under code/chat-ai-tools/, written against /sdk, retrieving as the user rather than as the system.

Bigger asks

  • "Build me a triage agent that can search the wiki and read tickets." — one file under code/agents/, system prompt and tool set together, plus whichever tools it names.
  • "Here is a CSV. Build me a schema and a connector for it."file-stats for the columns and their null counts, then a node schema and a connector, in one commit, because they only make sense together.

Prompts · sandboxes

A sandbox is a tool that hands out a filesystem

An AI tool whose code returns an ISandbox instead of a class of [Tool] methods. It does not answer a question — it describes a filesystem, and calling it runs a bash script against it. Sudo's own shape, handed to your workspace's assistant.

What the code declares

  • MountsLive (rebuilt before every script), Cached (built once per session), Scratch (empty and writable).
  • Commands — for what a file cannot be: an exact count over everything, a search, a consult, anything with an effect.
  • Description and FunctionName — what the model reads, and what it calls.

Why hand one out

  • A question nobody wrote a tool for gets answered by combining grep, awk, jq, sort and python.
  • The session persists across calls, so it is a place to work rather than a query with extra steps.
  • Reads go through the chatting user's own permissions, so a sandbox can never show someone data they could not otherwise see.

"Give the support assistant a sandbox over tickets and customers."

Prompts · front and back

One request, several surfaces, one commit

The interesting requests are the ones that do not belong to a single admin page. Say the outcome and let him pick the surfaces.

"Users should be able to filter tickets by product, and see the product on the ticket card."

Schema
A field on the node schema at config/schemas/nodes/Ticket.cs — a C# class, with its access control as attributes on the type and on the individual properties.
Backfill
A migration under code/migration-tasks/ that fills the field for nodes that already exist — build compiles the schema and the code using it together, so both go in one commit. After you approve it, run migration starts it and /proc/runs/<id>/log reports progress.
Search
The index settings under config/indexes/ that make the field facetable.
Front end
The node renderer and node style under config/schemas/nodes/renderers/ and styles/, plus config/interface.json — what the card shows and how the workspace presents it.

Prompts · operating

Running things and watching them

Starting something

  • "Run the nightly refresh now and tell me if it worked."run task "Nightly refresh", then reads /proc/runs/<id>/status and log as it progresses.
  • "Reindex Ticket and tell me when it is done."run reindex Ticket, then polls the run folder.

Changing something small

  • "Turn on the copy disclaimer and shorten chat retention to 30 days." — one config/*.json document, two values, one small diff.
  • "Delete the old ingest-from-ftp task." — removes the file and commits the deletion. Deleting a built-in is refused; naming something already gone is a warning, not an error.

Say what you want, not which surface. "Users should be able to filter tickets by product" beats "add a facet" — the right answer might be a facet, an index setting or a schema field, and he can look before deciding.

Limits

What Sudo will not do

Write without approval
There is no path from a draft to your workspace that does not pass through a diff you approved, and the approval is bound to the exact commit you were shown.
Modify your data
graph and query are read-only, run under the chatting admin's permissions, and skip node types that are never returned to clients. He reads your data as you can read it and writes none of it — a migration that backfills a field runs only after you approved it.
Reach the network
The sandbox has no route out.
Manage people
He can read access groups and reference one from a definition. Membership is yours, under Manage / Access.
Read a secret value
He can declare a secret and write code that reads it. He can never see one.
Anything else
No installing packages, no backups, no restarting the workspace, no licensing.

Limits

Your own permissions still apply, and they are narrower

Every session works the same way — Sudo drafts, you approve. What varies is what your account may do.

For a read-only administrator, commit and run refuse.

There is nothing for an approval to be an approval of, since the approving administrator would not be allowed to apply it either.

Accountability

Everything leaves a trail

Every shell call
Metered into the workspace's own metrics under an Admin Agent bucket, separately from ordinary chat tools.
Every applied commit
One entry in the configuration history, attributed to the administrator who approved it, visible under Manage / Access / Audit log and readable from the sandbox at /proc/audit.
Every code surface
Carries its own code history too, so an endpoint, AI tool, task or index changed through Sudo is reviewed and rolled back exactly like one changed by hand.

Everything he does is something you can do by hand, and every change he applies lands in the same tracked history as a manual one.

Teaching him

Conventions belong in a skill

His voice and boundaries are a skill in your workspace (sudo-persona), so they are visible and editable rather than hard-wired. Anything you would otherwise repeat at the start of every conversation belongs in one too.

How he is told to behave

  • Verify before acting — intent, target, likely impact.
  • Proceed on the small and reversible.
  • Ask first on the rest — destructive, security-sensitive, externally visible or materially ambiguous.
  • Smallest change that works — edit the lines that need editing.
  • No invented state, no unconfirmed success.

Getting more out of a session

  • Let him plan first on anything multi-step; /session/todo.md shows where he is.
  • Give him the file rather than describing it.
  • Ask for the diff early — "show me what that would change" catches a misunderstanding while it is still one file.
  • Correct in the chat, not in the review screen.
  • One commit per idea.

Read on

Where the detail is

Around it

The configuration Sudo edits is the same one the definitions export and git sync produce, so a change he applies travels between workspaces like any other.