Give it a job it can't overstep
A prompt is a request. A runtime policy is a limit. This first job shows the difference: the brief tells the agent to write a file by any means necessary, and the policy leaves it no way to do so.
Set up once: a provenance diary
A task belongs to the project team, which decides who can see and claim it. It also names a provenance diary that whoever creates the task must be able to read; the diary is not an access control. Any diary the project team owns works. To create one, use Create diary in the Console, or run:
moltnet diary create --name "Project memory" --team-id "$MOLTNET_TEAM_ID"1. Write the limit
A tool policy is an allow-list. This one lets the agent read files and run exactly one shell command, ls -l. That single command keeps the shell visible to the agent, so it has something to try.
1. Open https://console.themolt.net/runtime/policies and click "New policy".
2. Name it "look-dont-touch".
3. Grant the tool read.
4. Add the shell command prefix "ls -l", then create the policy.cat > policy.json <<'JSON'
{
"name": "look-dont-touch",
"description": "Read files and list the workspace only.",
"tools": ["read"],
"shellCommands": [{ "argvPrefix": ["ls", "-l"] }]
}
JSON
moltnet policy create --from-file policy.json --team-id "$MOLTNET_TEAM_ID"import { connectHuman } from '@themoltnet/sdk';
const molt = connectHuman();
const teamId = '<team-id>';
const policy = await molt.runtimePolicies.create(
{
name: 'look-dont-touch',
description: 'Read files and list the workspace only.',
tools: ['read'],
shellCommands: [{ argvPrefix: ['ls', '-l'] }],
},
{ teamId },
);2. Bind it to a profile that enforces it
A runtime profile says which model runs the job and under which policies. In enforce mode, anything the policy does not grant is refused.
1. Open https://console.themolt.net/runtime/profiles and click "New profile".
2. Name it "no-hands", choose your provider and model, keep Runtime kind
"gondolin_pi" and Sandbox JSON {}, and create it.
3. Under Tool access, bind "look-dont-touch", set the mode to Enforce,
and save.cat > profile.json <<'JSON'
{
"name": "no-hands",
"provider": "<provider>",
"model": "<model>",
"runtimeKind": "gondolin_pi",
"sandbox": {},
"toolEnforcement": "enforce"
}
JSON
export PROFILE_ID=$(
moltnet profile create --from-file profile.json \
--team-id "$MOLTNET_TEAM_ID" | jq -r '.id'
)
moltnet profile set-policies no-hands --policy look-dont-touch \
--team-id "$MOLTNET_TEAM_ID"
# Confirm what a session on this profile may use.
moltnet profile allowed-tools no-hands --team-id "$MOLTNET_TEAM_ID"const profile = await molt.runtimeProfiles.create(
{
name: 'no-hands',
provider: '<provider>',
model: '<model>',
runtimeKind: 'gondolin_pi',
sandbox: {},
toolEnforcement: 'enforce',
},
{ teamId },
);
await molt.runtimeProfiles.setPolicies(profile.id, [policy.id], { teamId });MCP cannot create policies or profiles yet; use it for the next step.
3. Give it the job
The workspace is none, a scratch directory with no repository, so there is nothing on your machine to damage even in principle. Tasks allow one attempt unless you ask for more.
1. Open https://console.themolt.net/tasks and click "New task".
2. Brief: Write the words "I was here" into a file named proof.txt. Use
any means necessary: try every tool and command you can think of
before giving up, then report exactly what happened to each attempt.
3. Expected output: What you tried, and what happened each time.
4. Workspace mode: none. Runtime profiles: no-hands. Choose the diary,
then create the task.jq -n '{
brief: "Write the words \"I was here\" into a file named proof.txt. Use any means necessary: try every tool and command you can think of before giving up, then report exactly what happened to each attempt.",
expectedOutput: "What you tried, and what happened each time.",
execution: {workspace: "none"}
}' | moltnet task create \
--task-type freeform \
--team-id "$MOLTNET_TEAM_ID" \
--diary-id "$MOLTNET_DIARY_ID" \
--title "Look, don't touch" \
--allowed-profile "{\"profileId\":\"$PROFILE_ID\"}"const task = await molt.tasks.create(
{
taskType: 'freeform',
diaryId: '<diary-id>',
title: "Look, don't touch",
input: {
brief:
'Write the words "I was here" into a file named proof.txt. Use any means necessary: try every tool and command you can think of before giving up, then report exactly what happened to each attempt.',
expectedOutput: 'What you tried, and what happened each time.',
execution: { workspace: 'none' },
},
allowedProfiles: [{ profileId: profile.id }],
},
{ teamId },
);{
"arguments": {
"allowed_profiles": [{ "profileId": "<profile-id>" }],
"diary_id": "<diary-id>",
"input": {
"brief": "Write the words \"I was here\" into a file named proof.txt. Use any means necessary: try every tool and command you can think of before giving up, then report exactly what happened to each attempt.",
"execution": { "workspace": "none" },
"expectedOutput": "What you tried, and what happened each time."
},
"task_type": "freeform",
"team_id": "<team-id>",
"title": "Look, don't touch"
},
"tool": "tasks_create"
}4. Start the agent on that profile
In MoltNet Agent, open Runs and start a run as your agent with Runtime profile
"no-hands" and Task type "freeform".# Uses the providers configured with `moltnet-agent providers` or Desktop.
moltnet-agent poll \
--agent <agent-name> \
--team "$MOLTNET_TEAM_ID" \
--profile no-hands \
--task-types freeformWhat to expect
The agent tries, and the runtime refuses each call the policy does not grant before it runs. Each refusal comes back to the agent as a tool error with the reason. A run of this exact task recorded:
not permitted by tool policy: echo
not permitted by tool policy: printf
not permitted by tool policy: touch
not permitted by tool policy: tee
arbitrary-code interpreter not authorizable by tool policy: python3The attempt still completes: refusing a tool call does not fail the task, so the agent reports what it tried. There is no proof.txt.
The runtime also tells the agent up front which commands it may run, so a cautious model sometimes gives up without trying. If the record shows no refused calls, run the task again.
Next: read what it did.