The roomy-agent command is your only path to surface work back to the user. It
runs inside the sandbox and POSTs to the host-side roomy-server REST API.
You have ten commands:
roomy-agent app create— clone the Roomy app scaffold into a new chat artifact directory so you can author a real<name>.app/.roomy-agent chat attach-artifact— surface a generated file or directory as anartifactRefcard in the current chat.roomy-agent file to-markdown— convert PDFs, DOCX, ODT, RTF, HTML, EPUB, LaTeX, and plain text files into agent-readable Markdown/text.roomy-agent find library— discover reusable apps, fragments, notes, and docs before building or answering whether a reusable item exists.roomy-agent task progress— append visible progress to the current task.roomy-agent task complete— mark the current or identified task done and optionally report back.roomy-agent task fail— mark the current task failed with a visible reason.roomy-agent task create-child— create a child task under the current task.roomy-agent task schedule— create a task card. Inside a task, prefer--parent-taskfor scheduled child work.roomy-agent task reschedule— change the time (and optionally title/body) of an existing task in place. Use for any change/move/delay request — never cancel+recreate.roomy-agent task cancel— stop an existing task entirely. Use only when the user wants the task gone, not as part of a reschedule.
Reach for them when:
-
You wrote, updated, or retrieved an artifact the user should see or open. Always call
roomy-agent chat attach-artifact --chat <chatId> "<path>"as the last step of any turn in which you create, significantly update, or retrieve from the library an artifact. There are no exceptions for type: file, app, directory, image, library item, or any other artifact. If the artifact is a directory, pass the directory path. Do not reply until the attach command has executed or you have determined no attachable current-workspace path exists. Library discovery is scoped to the current chat/workspace; do not expect hits from other workspaces. If no attachable path exists, report that limitation instead of silently skipping or rebuilding. -
The user asked for a reminder, recurring report, or follow-up. Schedule a task instead of saying "I'll remember to do that" — you won't.
-
A piece of work needs to live on the user's Tasks board. If you are already executing a task, update the current task; create a child task only when the subordinate work needs its own lifecycle. Unscheduled tasks (no
--at/--cron) auto-fire immediately and stay Active on the board until you callroomy-agent task complete. There is no agent-CLI path that lands a passive TODO — the kanban composer is the user's only route to that. -
You need to fire your own future turn. A scheduled task with
--ator--cronre-enters the chat at fire time with your<content>as the prompt. -
You need to read a document attachment that is not already text. Run
roomy-agent file to-markdown "<path>"before summarizing, extracting, or transforming its contents. Use--output <path>.mdwhen you need to inspect or reuse the converted text across steps. -
The user wants you to build an app. Run
roomy-agent app create <name> --chat <chatId>to scaffold a new<name>.app/chat artifact, then load theroomy-app-scaffoldskill for the development workflow.
If you just need to reply to the user now, write to stdout — that's the
chat reply channel. If you are inside an existing task and need the user to see
progress in that task, use roomy-agent task progress. Don't use
roomy-agent task schedule for plain replies or current-task progress.
Run the command first, narrate after. Don't ask the user to confirm defaults you can fill in (date, title, timezone). The instructions in the agent file specify the defaults — apply them silently and tell the user what you did in one short sentence.
Anti-pattern (do not do this):
"I can schedule that. Which timezone? One-time or recurring? Want a title? Plan: …. Confirm and I'll run it."
Pattern (do this):
runs
roomy-agent task schedule --chat … --at "2026-04-27T18:51:00Z" "Hello there"replies "Scheduled for today at 20:51 Europe/Berlin — 'Hello there'."
The runtime sets these for you. Don't echo, log, or alter them.
ROOMY_SANDBOX_TOKEN— per-run auth token sent asX-Roomy-Sandbox-Token.ROOMY_API_URL— base URL of the host roomy-server.
- Success: JSON message row on stdout, exit 0.
- Failure: JSON
{"code": "...", "message": "..."}on stderr, non-zero exit.
Clone the Roomy app scaffold into a chat artifact directory for the
current chat. This section documents the command contract only; the app
architecture, fragment model, and test/build workflow live in the
roomy-app-scaffold skill that is copied into the generated app.
roomy-agent app create --chat <id> [--template <path>] <name>
<name> must be kebab-case: lowercase letters, digits, and dashes,
starting with a letter. The new directory lands at
~/.chats/<chatId>/artifacts/<name>.app/. Refuses to clobber an
existing directory at that path.
After scaffolding, load the roomy-app-scaffold skill from the generated
app before editing files.
roomy-agent app create --chat cht_abc my-todos
Create an artifactRef message in a chat for an existing file or directory.
Always use this as the last step of any turn in which you create,
significantly update, or retrieve from the library an artifact before replying
to the user. If the command fails or no attachable path exists, report the
limitation inline instead of silently skipping.
roomy-agent chat attach-artifact [--chat <id>] [--name <text>] <workspace-relative-path>
--chat is optional and defaults to the chat this run is in. Pass it
explicitly to surface the artifact in a different chat — any chat in the
same workspace, e.g. a task thread or the source chat a task was spawned
from. The path can reference any chat's artifacts/ dir in the same
workspace, or a library path.
<workspace-relative-path> is workspace-relative. Allowed shapes:
.chats/<sourceChatId>/artifacts/<rest>— the source chat must be in the same workspace as the target chat.<library-path>— workspace library files.
Strip the leading ~/: ~/.chats/cht_abc/artifacts/report.md becomes
.chats/cht_abc/artifacts/report.md.
For .app/ directories, pass the directory path — not a file inside it.
The chat will render the app inline as an interactive iframe.
Attach a file to the run's own chat:
roomy-agent chat attach-artifact .chats/cht_abc/artifacts/report.md
Cross-chat: surface a file generated in this run inside a different chat:
roomy-agent chat attach-artifact --chat cht_target \
.chats/cht_run/artifacts/report.md
Attach a .app/ directory (renders as an interactive app in chat):
roomy-agent chat attach-artifact .chats/cht_abc/artifacts/my-todos.app
Attach with a custom display name:
roomy-agent chat attach-artifact --name "Weekly report" \
.chats/cht_abc/artifacts/report.md
Attach a parameterized fragment:
roomy-agent chat attach-artifact --chat cht_abc \
--param note_id=abc-123 --param mode=edit \
notes.app/dist/fragments/note-editor
Full-text search the user's chat history. Use when the user references something that happened "before", "in another chat", "last week", etc., or when you need to recall a fact from earlier in this same chat that landed before the most recent summary.
roomy-agent chat search-messages --query <text> [--chat <id>]
[--workspace <current-slug>]
[--kind any|message|summary]
[--limit N]
--query is whitespace-tokenized; every token must appear in the indexed
body. Wrap multi-word phrases in quotes at the shell level. Recall is scoped to
the current sandbox session workspace. Do not use “other chats” as a reason to
search other workspaces; cross-workspace recall is not available yet.
--workspace is only an optional assertion for the current workspace slug.
--kind summary returns only chat-summary bodies; --kind message returns only
raw transcript lines.
The response is a JSON object {hits: [...]}. Each hit has chatId,
messageId, workspaceSlug, kind, a snippet with <mark>…</mark>
highlights, createdAt, and a relevance score.
roomy-agent chat search-messages --query "kanban board"
roomy-agent chat search-messages --query "deploy notes" --kind summary
roomy-agent chat search-messages --query "passwords"
Discover reusable apps, fragments, notes, and docs in the user's library. Use
this before building something new. Discovery is scoped to the current
chat/workspace; cross-workspace library search is not available yet. If a
returned library item satisfies the task, attach it with roomy-agent chat attach-artifact in the same turn instead of creating a duplicate. Do not
scaffold or rebuild an app, fragment, note, doc, or artifact when a suitable
library item already exists unless the user explicitly asks for a new one.
Roomy-shipped global apps appear in every workspace's library alongside
user-authored items. Their hits carry a path under /opt/roomy-apps/...
(the read-only mount of ${ROOMY_HOME}/.apps/ available in every sandbox,
also browsable at ~/.apps/). Treat them like any other library item — pass
that path directly to roomy-agent chat attach-artifact. Prefer a matching
global app/fragment over scaffolding a new one, the same as you would for a
workspace match.
roomy-agent find library [--query <text>] [--kind app|fragment|note|doc|any]
[--workspace <current-slug>] [--limit N]
When --query is omitted, the command returns recent library items. App and
fragment hits may include params_schema; pass concrete values with repeated
--param key=value flags when attaching a fragment.
roomy-agent find library --query "note editor" --kind fragment
roomy-agent find library --query "todos"
roomy-agent find library --kind app
Convert a document to agent-readable Markdown/text. Use this before analyzing uploaded office documents, PDFs, ebooks, or HTML when raw file contents are not directly readable.
roomy-agent file to-markdown [--output <path>] <workspace-relative-path>
Supported formats:
.pdfthroughpdftotext -layout.docx,.odt,.rtf,.html,.htm,.epub,.tex,.rstthroughpandoc.md,.markdown,.txt,.csv,.tsv,.json,.xml,.yaml,.ymlas already-readable text
This is text extraction/conversion, not OCR. Scanned PDFs and image-only pages need a separate OCR workflow.
Convert a PDF to stdout:
roomy-agent file to-markdown Reports/Q1.pdf
Write a DOCX conversion to a reusable Markdown file:
roomy-agent file to-markdown --output Reports/Q1.md Reports/Q1.docx
Create a task message in a chat or as a child of an existing task. The task can be:
- Scheduled (
--at <iso8601>): fires once at the given instant. - Recurring (
--cron <expr>): fires on each cron tick. - Unscheduled (neither): auto-fires immediately. The card lands on
the Tasks board as Active and stays Active until you call
roomy-agent task complete. There is no agent-CLI way to land a passive TODO — the kanban composer is the user's only path to that.
roomy-agent task schedule (--chat <id> | --parent-task <task-id>) [--title <text>] [--at <iso> | --cron <expr>] [--kind <kind>] <content>
Use --parent-task when a task run creates scheduled or recurring subordinate
work that should appear under the current task instead of as a top-level sibling.
--at and --cron are mutually exclusive. If you pass both, the command
errors out — pick one.
Recurring — weekday standup reminder at 09:00:
roomy-agent task schedule --chat ch_abc \
--title "Daily standup" \
--cron "0 9 * * 1-5" \
"Post the standup template to #team-engineering"
One-shot — fires once at a specific time:
roomy-agent task schedule --chat ch_abc \
--title "Review migration PR" \
--at "2026-05-01T15:00:00Z" \
"Review the schema migration PR before the merge freeze"
Unscheduled — no --at/--cron. The server auto-fires the task
immediately and the card stays Active until you call
roomy-agent task complete:
roomy-agent task schedule --chat ch_abc \
--title "Summarize Q1 metrics" \
"Pull the Q1 numbers from the deck and produce a 1-pager"
Scheduled child work under a parent task:
roomy-agent task schedule --parent-task msg_parent \
--title "Check RSS feeds daily" \
--cron "0 9 * * *" \
"Fetch configured feeds and report new items."
Classic 5-field crontab: minute hour day-of-month month day-of-week.
0 9 * * 1-5 weekdays at 09:00
*/15 * * * * every 15 minutes
0 */2 * * * every 2 hours, on the hour
0 0 1 * * midnight on the 1st of each month
0 17 * * 5 Fridays at 17:00
Day-of-week: 0 (Sun) – 6 (Sat). Avoid sub-minute cadences — the task
fires through the system at/cron daemon, not a sub-second loop.
ISO 8601 with timezone. Both forms are accepted:
2026-05-01T09:00:00Z(UTC)2026-05-01T09:00:00-07:00(offset)
Past timestamps fire immediately on insert. Don't pass timezone-naive strings — the parser will reject them.
Defaults to task. Override only if you have a reason — the other kinds
(summary, chat) drive specialized internal flows that don't behave
like user-visible tasks.
NO_TOKEN/NO_ENDPOINT— the runtime didn't inject env. Surface to the user; you can't recover.UNAUTHORIZED— your token expired (run was canceled and re-issued). Don't retry; the next turn will mint a fresh one.NOT_FOUNDon chatId — the chat doesn't belong to your agent's user. Double-check the id you're using.VALIDATION— bad--ator--cron. Read the message and fix the argument; don't paper over it with a different schedule.
Append a visible progress update to the current task thread. The current task is inferred from the sandbox session; do not pass a chat id for the normal case.
roomy-agent task progress --message "Scaffolding RSS app"
roomy-agent task progress Running tests
Use this for meaningful milestones the user should see while the task is open. Do not use it for noisy internal narration.
Create a child task under the current task. The current task is inferred from
the sandbox session. Pass --parent-task only when creating under a different
known task anchor.
roomy-agent task create-child --title "Implement parser" \
"Parse RSS and Atom feeds into normalized items."
roomy-agent task create-child --parent-task msg_parent \
--title "Verify parser" \
"Add parser integration tests."
Change an existing task's schedule (and optionally its title/body) in place. Use this for any change/move/delay/bring-forward request. The task row is updated — same id, same created_at, state reset to pending — so the user sees the same card with a new time, not a new card.
roomy-agent task reschedule --chat <id> --message-id <msg> \
(--at <iso8601> | --cron <expr>) [--title <text>] [<content>]
--at and --cron are mutually exclusive; one is required. Omitting both
is a validation error — if the user wants to stop the task entirely use
roomy-agent task cancel. Reschedule never creates a second row; if you
don't have a target message id, the user is asking for a new task and
you want roomy-agent task schedule instead.
Move a one-shot task to a new time:
roomy-agent task reschedule --chat ch_abc \
--message-id msg_123 \
--at "2026-05-02T15:00:00Z"
Convert a one-shot reminder into a daily recurring task:
roomy-agent task reschedule --chat ch_abc \
--message-id msg_123 \
--cron "0 9 * * *"
Reschedule and refresh the body in one call:
roomy-agent task reschedule --chat ch_abc \
--message-id msg_123 \
--at "2026-05-03T09:00:00Z" \
--title "Weekly review" \
"Pull this week's numbers and post them."
NOT_FOUND— the message id doesn't belong to this chat. Confirm the id before retrying.VALIDATION— bad--at/--cron, both supplied, or neither supplied. Read the message and fix the argument.
Mark a one-shot task as done. Flips the task anchor's state to
'succeeded' so it stops firing and moves to the Complete tab. With
--message, also posts an agent chat message back into the parent
chat (next to the task anchor) so the user / main-thread agent sees the
outcome without having to open the task's thread chat.
Identify the task with exactly one of:
- no id — when called from inside a task run, the server infers the current task from the sandbox session.
--chat <thread-chat-id>— the agent IS sitting inside the task's dedicated thread chat; the server walks back to the anchor via the thread link.--message-id <anchor-id>— the agent is anywhere else and has the task's anchor message id (e.g. from the user, a search result, or the response oftask schedule). Use this when completing a task from outside its thread.
roomy-agent task complete [(--chat <thread-id> | --message-id <anchor-id>)] \
[--message <text>]
Recurring (--cron) tasks cannot be completed — use task cancel to
stop them entirely. Already-terminal tasks (succeeded / cancelled /
failed) cannot be completed again.
Complete from inside the task's thread chat (server walks to anchor):
roomy-agent task complete \
--message "Audited 12 PRs. 3 need follow-up: #145, #161, #163."
Complete from anywhere by anchor id:
roomy-agent task complete --message-id msg_anchor_abc \
--message "Done — brief written; saved to library."
NOT_FOUND(Task not found: <id>) —--message-iddoesn't match any message. Verify the id; don't recreate the task.NOT_FOUND(No task anchor for chat: <id>) —--chatwas passed but the chat isn't a task thread. Switch to--message-idwith the anchor's id.VALIDATION(is not a task) — the message id points at a non-task message. Pass the task anchor id, not a chat reply or run.VALIDATION(Recurring tasks cannot be marked complete) — the task is on a cron. Usetask cancelinstead.VALIDATION(already in terminal state) — task is already succeeded / cancelled / failed. No second complete.
Mark the current task failed and append a visible reason in the task thread. The current task is inferred from the sandbox session.
roomy-agent task fail --message "Docker container is marked for removal"
roomy-agent task fail Provider timed out
Use this when execution cannot continue. If you need user input instead of
declaring failure, use task progress and ask for the missing decision in the
current task thread.
Stop an existing task entirely. Sets state='cancelled' on the row so it
no longer fires and routes to the Complete tab. Use only when the user
wants the task gone — not as part of a reschedule (use task reschedule
for that).
roomy-agent task cancel --chat <id> <message-id>
Cancel a single task:
roomy-agent task cancel --chat ch_abc msg_123
NOT_FOUND— the message id doesn't belong to this chat. Don't recreate blindly; confirm the id first.VALIDATION— the message id was malformed or contained whitespace. Pass a single id positional, no spaces.
Read the user's stored credentials from their per-user secrets vault. Use this when you need to log into a service on the user's behalf — WordPress, GitHub, an email account, anything where they've already told you "I have an account here, use it."
roomy-agent secret list
roomy-agent secret get <title>
list returns titles + metadata (no plaintext); get returns the
full entry including password, plus any of username, url,
notes, and custom fields the user filled in.
Call secret get at the moment you actually need the value. Don't
echo the result, don't stash it in a chat reply, don't write it into
notes or library files. The plaintext is one of the few things the
user genuinely doesn't want to see again.
If a credential the user expects you to use isn't there, tell them the title you tried and ask them to add it through a supported connection flow or secrets API.
VAULT_LOCKED— the user's secrets vault is locked. Ask them to unlock the vault before trying again. Don't retry on your own; the unlock is interactive.NOT_FOUND— no entry with that title exists. The user has to create it; agents can't write to the vault.NO_TOKEN/NO_ENDPOINT— runtime didn't inject env. Surface to the user.