A session is a conversation with Claude Code or Codex in its own cloud environment. The agent keeps working when you close the page or disconnect.
In the dashboard, describe the task on Home and click New session. From a terminal:
1
ellipsis --model claude-opus-5-5 -e cloud_agent_environment "Add an empty-body test in api-repo. Run it; do not commit."
From code:
1
import os
2
from ellipsis import Ellipsis
3
4
client = Ellipsis(api_key=os.environ["ELLIPSIS_API_TOKEN"])
5
handle = client.sessions.run(
6
environment="cloud_agent_environment",
7
budget={"session": 5},
8
claude_code={
9
"model": "claude-opus-5-5",
10
"prompt": "Add an empty-body test in api-repo. Run it; do not commit.",
11
},
12
)
13
print(handle.id)
1
import { Ellipsis } from '@ellipsis-dev/sdk';
2
3
const client = new Ellipsis({
4
apiKey: process.env.ELLIPSIS_API_TOKEN!,
5
});
6
const handle = await client.sessions.run({
7
environment: 'cloud_agent_environment',
8
budget: { session: 5 },
9
claude_code: {
10
model: 'claude-opus-5-5',
11
prompt:
12
'Add an empty-body test in api-repo. Run it; do not commit.',
13
},
14
});
15
console.log(handle.id);
Replace cloud_agent_environment and api-repo with your environment and repository; without an environment, the session uses the default environment. budget caps the session at $5. Keep the session ID to check on it later. To set up the client, see the Python or TypeScript SDK and API authentication.
The dashboard and the CLI show messages and tool calls as they happen. To reattach the CLI to a running session, run ellipsis session get <session-id> --watch. From code, wait for the turn that answers your prompt:
1
session = handle.wait(timeout=900)
2
print(session.turn.status, session.turn.reason, session.turn.detail)
3
4
for record in client.sessions.records(handle.id):
5
print(record.kind, record.payload)
1
const session = await handle.wait({ timeoutMs: 900_000 });
2
console.log(session.turn?.status, session.turn?.reason, session.turn?.detail);
3
4
for await (const record of await client.sessions.records(handle.id)) {
5
console.log(record.kind, record.payload);
6
}
wait() returns when the turn reaches a final status: completed, failed, stopped, or cancelled. Check turn.status before treating the task as done; reason and detail explain a failed or cancelled turn. A timeout stops your client from waiting, not the agent. To stream messages as they happen, see the Python or TypeScript SDK; for what each status means, see Lifecycle.
1
handle = client.sessions.handle("your-session-id")
2
print(handle.session.conversation.state, handle.session.turn)
1
const handle = await client.sessions.handle('your-session-id');
2
console.log(handle.session.conversation.state, handle.session.turn);
Get a handle by ID at any time, for example after your application restarts. turn is the turn in progress, or the latest one when none is running.
In the dashboard, type in Reply to the agent... and click Send. In the CLI, type in the session view. From code:
1
message = handle.send("Add a test for an invalid content type too.")
2
session = handle.wait(timeout=900)
3
print(message.turn_id, session.turn.status)
1
const message = await handle.send(
2
'Add a test for an invalid content type too.'
3
);
4
const session = await handle.wait({ timeoutMs: 900_000 });
5
console.log(message.turn_id, session.turn?.status);
A follow-up continues the same conversation and workspace. The message gets its turn the moment it is received, and wait() then waits on that turn; a message sent while a turn is running is answered after it. Only the person who started a session can message it. Sessions started by a mention take replies in their GitHub, Slack, or Linear thread. A closed session can't take follow-ups; conversation.prompting says whether a message would be accepted, see Lifecycle.
1
task = client.sessions.run(
2
environment="cloud_agent_environment",
3
claude_code={
4
"model": "claude-opus-5-5",
5
"prompt": "Run request-validation tests in api-repo and report failures.",
6
},
7
conversation={"interactive": False},
8
)
9
result = task.wait(timeout=900)
10
print(task.id, result.turn.status, result.conversation.state)
1
const task = await client.sessions.run({
2
environment: 'cloud_agent_environment',
3
claude_code: {
4
model: 'claude-opus-5-5',
5
prompt:
6
'Run request-validation tests in api-repo and report failures.',
7
},
8
conversation: { interactive: false },
9
});
10
const result = await task.wait({ timeoutMs: 900_000 });
11
console.log(task.id, result.turn?.status, result.conversation.state);
Set conversation.interactive to false when you won't send follow-ups. The conversation closes when its turn ends and its environment is deleted; its messages and results stay available. To save a task and run it again or on a schedule, use Agents.
1
diff = client.sessions.diff(handle.id)
2
for file in diff.files:
3
print(file.full_name, file.path, file.patch)
4
print("Omitted paths:", diff.omitted_paths)
5
6
git = client.sessions.git(handle.id)
7
for repo in git.repos:
8
print(repo.full_name, repo.commits, repo.prs)
1
const diff = await client.sessions.diff(handle.id);
2
for (const file of diff.files) {
3
console.log(file.full_name, file.path, file.patch);
4
}
5
console.log('Omitted paths:', diff.omitted_paths);
6
7
const git = await client.sessions.git(handle.id);
8
for (const repo of git.repos) {
9
console.log(repo.full_name, repo.commits, repo.prs);
10
}
Get the session's uncommitted changes and the commits and pull requests it made. Files left out of the diff are listed in omitted_paths.
1
session = handle.refresh()
2
print("Cost (USD):", session.cost.total / 100_000)
3
print("Budget (USD):", session.budget)
1
const session = await handle.refresh();
2
console.log('Cost (USD):', session.cost.total / 100_000);
3
console.log('Budget (USD):', session.budget);
cost.total is in thousandths of a cent, so divide by 100,000 for dollars. budget is in dollars, and follow-ups share it. Each turn carries its own cost and tokens; list them with GET /v1/sessions/{session_id}/turns. See Pricing for rates, or download the session history.
Click Stop in the dashboard. In the CLI, type /stop in the session view or run ellipsis session stop <session-id>. From code:
1
session = handle.stop()
2
print(session.turn.status, session.turn.stopped)
1
const session = await handle.stop();
2
console.log(session.turn?.status, session.turn?.stopped);
Stopping ends the running turn with stopped, not the conversation: the session can still take follow-ups. Stopping a session with no turn pending or running fails with 409. Disconnecting doesn't stop the agent.