A3S Docs
A3S Code

Commands & Scheduling

Slash commands, BTW ephemeral queries, and recurring scheduled tasks

Commands & Scheduling

Sessions intercept special inputs before the LLM sees them. This covers three related capabilities: slash commands for session control, btw() for ephemeral side questions, and the scheduler for recurring prompts.

Slash Commands

Type /help in any session to list all available commands. Commands are intercepted before the LLM — they execute instantly and do not add a turn to conversation history.

CommandDescription
/helpList available commands
/model [provider/model]Show or switch the current model
/costShow token usage and estimated cost
/historyShow conversation turn count and token stats
/clearClear conversation history
/compactManually trigger context compaction
/toolsList registered tools
/mcpList connected MCP servers and their tools
/loop [interval] <prompt>Schedule a recurring prompt (default interval: 10m)
/cron-listList all scheduled recurring prompts
/cron-cancel <id>Cancel a scheduled task by ID

List All Commands (SDK)

const commands = session.listCommands();
for (const cmd of commands) {
  const usage = cmd.usage ? `  usage: ${cmd.usage}` : '';
  console.log(`/${cmd.name.padEnd(15)} ${cmd.description}${usage}`);
}
commands = session.list_commands()
for cmd in commands:
    usage = f"  usage: {cmd['usage']}" if cmd.get('usage') else ''
    print(f"/{cmd['name']:15s} {cmd['description']}{usage}")

Custom Commands

Register custom slash commands handled before the LLM:

function statusHandler(args: string, ctx: CommandContext): string {
  console.log(`Model: ${ctx.model}, History: ${ctx.historyLen} msgs, args: ${args}`);
  return `Status: OK`;
}

session.registerCommand("status", "Show session status", statusHandler);

const result = await session.send("/status hello");
console.log(result.text);
// Command 'status' executed successfully

The handler receives:

  • args — string with everything after the command name
  • ctx — object with sessionId, model, historyLen, totalTokens, totalCost, toolNames, and mcpServers

Due to napi-rs limitations, the return value from the handler function is not currently captured. Use console.log() or other side effects in your handler. Future versions will support return value capture.

def status_handler(args: str, ctx: dict) -> str:
    return (
        f"Model: {ctx['model']}, "
        f"History: {ctx['history_len']} msgs, "
        f"args: {args!r}"
    )

session.register_command("status", "Show session status", status_handler)

result = session.send("/status hello")
print(result.text)
# Model: openai/gpt-4o, History: 2 msgs, args: 'hello'

The handler receives:

  • args — string with everything after the command name
  • ctx — dict with session_id, model, and history_len

BTW — Ephemeral Side Questions

The btw() method lets you ask side questions without affecting conversation history. Useful for quick lookups, clarifications, or context checks that shouldn't be part of the main task flow.

Key properties:

  • Questions and answers are never added to conversation history
  • Uses a read-only snapshot of current history for context
  • Safe to call concurrently with ongoing send() or stream() operations
  • No tool execution — answers are based on LLM knowledge + current context only
  • Returns immediately with answer and token usage
// Main conversation
const result = await session.send('Explain the authentication system');
console.log(result.text);

// Quick side question (not added to history)
const btw = await session.btw('What is the capital of France?');
console.log(btw.answer);        // "Paris"
console.log(btw.totalTokens);   // token usage for this query

// Continue main conversation — btw question is not in history
const result2 = await session.send('Show me the login code');
# Main conversation
result = session.send("Explain the authentication system")
print(result.text)

# Quick side question (not added to history)
btw = session.btw("What is the capital of France?")
print(btw.answer)        # "Paris"
print(btw.total_tokens)  # token usage for this query

# Continue main conversation — btw question is not in history
result2 = session.send("Show me the login code")

BtwResult

Prop

Type

Use Cases

  • Quick lookups: "What's the syntax for X in language Y?"
  • Clarifications: "What does this error code mean?"
  • Context checks: "What files are in the current directory?"
  • Side calculations: "What's 15% of 1000?"
  • General knowledge: Questions unrelated to the main task

Scheduled Tasks

Sessions support recurring prompts via the /loop slash command or the programmatic scheduler API. Scheduled tasks fire after each send() call when their interval has elapsed. The background ticker starts lazily on the first send() and stops automatically when the session is dropped.

Limits: Max 50 scheduled tasks per session. Tasks auto-expire after 3 days. A reentrance guard prevents nested firing.

Schedule a Recurring Prompt

// Via /loop slash command
const r = await session.send('/loop 30s check deployment status');
console.log(r.text);
// Scheduled [a1b2c3d4]: "check deployment status" — fires every 30s

// Programmatic (interval in seconds)
const taskId = session.scheduleTask('summarize recent commits', 300);  // every 5 min
console.log(`Scheduled: ${taskId}`);
# Via /loop slash command
r = session.send('/loop 30s check deployment status')
print(r.text)
# Scheduled [a1b2c3d4]: "check deployment status" — fires every 30s

# Programmatic (interval in seconds)
task_id = session.schedule_task('summarize recent commits', 300)  # every 5 min
print(f'Scheduled: {task_id}')

Interval syntax:

FormatExampleMeaning
Seconds30sEvery 30 seconds
Minutes5mEvery 5 minutes
Hours2hEvery 2 hours
Days1dEvery day
Leading/loop 5m <prompt>Interval before the prompt
Trailing/loop <prompt> every 5mevery clause at end
Default/loop <prompt>Every 10 minutes

List Scheduled Tasks

// Programmatic
const tasks = session.listScheduledTasks();
for (const t of tasks) {
  console.log(`[${t.id}] every ${t.intervalSecs}s — fires in ${t.nextFireInSecs}s — "${t.prompt}"`);
}

// Via slash command
const r = await session.send('/cron-list');
console.log(r.text);
# Programmatic
tasks = session.list_scheduled_tasks()
for t in tasks:
    print(f"[{t['id']}] every {t['interval_secs']}s "
          f"— fires in {t['next_fire_in_secs']}s "
          f"— \"{t['prompt']}\"")

# Via slash command
r = session.send('/cron-list')
print(r.text)

Cancel a Scheduled Task

// Programmatic
const ok = session.cancelScheduledTask(taskId);
console.log(`Cancelled: ${ok}`);  // true

// Via slash command
const r = await session.send(`/cron-cancel ${taskId}`);
console.log(r.text);  // Cancelled task [a1b2c3d4]
# Programmatic
ok = session.cancel_scheduled_task(task_id)
print(f'Cancelled: {ok}')  # True

# Via slash command
r = session.send(f'/cron-cancel {task_id}')
print(r.text)  # Cancelled task [a1b2c3d4]

ScheduledTaskInfo Fields

Prop

Type

On this page