Skip to main content

In-Chat Commands

These commands work inside chat channels and interactive agent sessions:

CommandDescription
/newStop the current task and start a new conversation
/stopStop the current task
/restartRestart nanoinfra
/statusShow the running nanoinfra version and model, what the last turn cost in tokens, context use, session message count, uptime, and the number of active tasks
/modelShow the current model and available model presets
/model <preset>Switch and persist the model preset for the current session
/dreamRun Dream memory consolidation now
/dream-logShow the latest Dream memory change
/dream-log <sha>Show a specific Dream memory change
/dream-restoreList recent Dream memory versions
/dream-restore <sha>Restore memory to the state before a specific change
/dream-promptShow the instructions that guide Dream for memory
/dream-prompt initCreate an editable Dream memory guide at prompts/dream.md
/skillList enabled skills and their descriptions
/triggerShow local trigger usage
/trigger <name>Create a named local trigger for the current chat session
/pairingList pending pairing requests
/pairing listList pending pairing requests. /pairing with no subcommand does the same
/pairing approve <code>Approve a pairing code
/pairing deny <code>Deny a pending pairing request
/pairing revoke <user_id>Revoke a previously approved user on the current channel
/pairing revoke <channel> <user_id>Revoke a previously approved user on a specific channel
/approve <request-id>Approve one suspended remote action
/deny <request-id> <reason>Refuse one suspended remote action
/helpShow available in-chat commands

Pairing​

nanoinfra automatically replies with a pairing code (like ABCD-EFGH) when someone sends it a DM and is not on the allowlist. This covers a new user, and an existing user on a new channel. The code expires in 10 minutes. To grant them access:

/pairing approve ABCD-EFGH

To see who is waiting, use /pairing. To remove someone later, use /pairing revoke <user_id>. The /pairing list output holds the user IDs.

See Configuration: Pairing for the full setup guide.

Approve or Refuse a Suspended Action​

The capability gate suspends an unusual remote action and waits for a person. nanoinfra sends the suspended action to every approver who may answer it, with the command and the host list the executor rendered. Answer with the request id it carries:

/approve 0123456789abcdef
/deny 0123456789abcdef this host is in a maintenance window

Three things to know before you rely on this:

  • A pairing approval is not an approval here. /pairing decides who can reach nanoinfra. gates.approvers decides whose answer counts, and it lives in config that a git review covers. An approver needs both.
  • You cannot answer a request your own chat raised. The answer has to arrive on a path other than the one that asked. That rule is the point: one compromised account must not hold both halves.
  • The model never sees either command. Both run before the turn reaches a model, so the text stays out of the conversation.

Read Capability Gates: Answer From a Chat Channel for the identity rules and for how to add a second channel.

Model Presets​

Use /model to inspect the current runtime model:

/model

The response shows the current session's model and preset, plus the available preset names. Named presets come from the top-level modelPresets config and are the recommended way to configure model choices. default is always available and represents the model settings from direct agents.defaults.* fields.

To switch presets for future turns:

/model fast
/model deep
/model default

Preset names come from the top-level modelPresets config. Switching affects only the current session and persists the selection in that session, so later turns keep using it across process restarts. It does not rewrite config.json, does not change other sessions, and does not alter an in-progress turn's captured model. Sessions without a saved selection follow agents.defaults.modelPreset (or the implicit default preset when it is omitted). See Configuration: Model presets for setup details.

Local triggers​

Use /trigger <name> when a local script or another service must send a message into the current chat session later. You must give a name. Plain /trigger only shows the usage hint.

Create the trigger from the chat where future messages should arrive:

/trigger PR review

nanoinfra replies with a trigger ID and a command shaped like:

nanoinfra trigger trg_8K4P2Q9X "Review PR #4502"

The reply also states that the trigger is not rehearsed. nanoinfra runs a scheduled automation once at creation and previews every gated action, so you learn the permission it needs before its schedule does. A trigger carries no stored message, because its content arrives from whoever fires it. Rehearsing an invented message would propose a standing grant for a command the real firing may never use, so nanoinfra says so instead of guessing. Fire it once while you are watching to learn what it needs. See automations.md#creating-one-rehearses-it.

Replace "Review PR #4502" with the message you want nanoinfra to receive. nanoinfra binds the trigger to the session where you created it, so the message goes back to that same chat. Keep nanoinfra gateway running so nanoinfra can deliver trigger messages. The trigger message starts an automation turn recorded in that session with the message you passed to the CLI. nanoinfra does not treat it as a normal user message. If that session is already running a turn, the trigger waits until the session is idle rather than joining the active turn.

nanoinfra stores trigger deliveries in the workspace until their linked agent turn finishes successfully. If nanoinfra exits after claiming a delivery but before the turn completes, the next start requeues that delivery. This is an at-least-once local queue. A delivery may run more than once if the process exits at the wrong time, so external scripts should make repeated trigger messages safe. If the delivery reaches nanoinfra and the agent turn fails, Automations marks the delivery failed instead of retrying forever.

For longer or generated content, omit the message argument and pipe stdin:

printf '%s\n' "Review the latest failed CI job" | nanoinfra trigger trg_8K4P2Q9X

If an external webhook should send a message into nanoinfra, run your own small webhook service. Have it call the trigger command after it builds the final message:

nanoinfra trigger <trigger-id> "<message>"

If you run multiple nanoinfra instances, pass the same config or workspace selector used by the gateway:

nanoinfra trigger --config ./bot-a/config.json trg_8K4P2Q9X "Nightly report"
nanoinfra trigger --workspace ./bot-a/workspace trg_8K4P2Q9X "Nightly report"

Manage triggers from the WebUI Automations view. You can search, pause, resume, rename, delete, and copy the trigger command there. A session may have multiple triggers, just like it may have multiple scheduled automations.

See Automations for how local triggers fit with scheduled automations, heartbeat, and gateway delivery.

Periodic Tasks​

The heartbeat is not a chat command. It is a protected cron job nanoinfra registers, and HEARTBEAT.md in your workspace drives it. It is the one automation type you edit as a file rather than create from a chat.

See Gateway Heartbeat for the interval, the notification gate and keepRecentMessages. See Choose an Automation Type for when a heartbeat is the right choice rather than a scheduled automation.

Setup: edit ~/.nanoinfra/workspaces/default/HEARTBEAT.md. nanoinfra onboard creates it for you:

## Active Tasks

- Check weather forecast and notify me only if storms are expected
- Scan inbox for urgent emails and notify me if any are found

nanoinfra can also manage this file itself. Ask it to "add a periodic background check", or to "check this periodically but only notify me if something changes", and it updates HEARTBEAT.md for you. Delete completed tasks from the file rather than moving them to another section.

You can change the interval or disable the built-in heartbeat in ~/.nanoinfra/config.json:

{
"gateway": {
"heartbeat": {
"enabled": true,
"intervalS": 1800
}
}
}

The heartbeat job appears in cron(action="list") as heartbeat, but nanoinfra manages it and the cron tool cannot remove it. To stop it, set gateway.heartbeat.enabled to false and restart the gateway.

Note: nanoinfra must be running (nanoinfra gateway). You must also have chatted with nanoinfra at least once, so it knows which channel to deliver to.