# AgentMove

> Moves: a coding agent's session on a laptop (Claude Code, Codex, OpenCode, Hermes or OpenClaw) copies itself onto a NoClick agent and carries on there. The laptop keeps its own session.

Your side makes the move and follows it; the agent in the session does the rest, from the guide its prompt names:

```python
move = noclick.AgentMove.create(name="Docs fixer")
print(move.prompt)        # paste into the session you want moved
...
move.refresh()
print(move.status, move.arrived["files"])   # moving, what it carried so far
print(move.agent_id, move.conversation)     # once done
```

The agent's side runs with the move's own key, which its code is redeemed for once (`AgentMove.redeem`): it can
reach nothing but the move, and ends with it.

```python
key = noclick.AgentMove.redeem("nc_move_...", host="ana-mbp")
moving = noclick.AgentMove.current(client=noclick.Client(api_key=key))
moving.upload_session(tar_bytes, harness="claude_code", cwd="/Users/ana/code/acme")
moving.finish()
```

## AgentMove

```typescript
class AgentMove
```

A move from a laptop. Make one with `create` (its `code` and `prompt` come only then), follow it with
`refresh` on each `platform:resource` frame of kind `agent_move`, and `cancel` it to call it off.

| Attribute | Type | Description |
| --- | --- | --- |
| `id` | `string` |  |
| `status` | `AgentMoveStatus` | One of `waiting`, `moving`, `finishing`, `done`, `failed`, `canceled`, `expired`. |
| `code` | `string | null` | The one-time code (from `create` only). |
| `prompt` | `string | null` | What a person pastes into the session to move (from `create` only). |
| `guideUrl` | `string` | The guide the moving agent follows. |
| `workspaceId` | `string | null` | The space the agent joins. |
| `draft` | `JsonObject` | What the move was made with: `name`, `harness`, `model`, `model_connection`. |
| `source` | `AgentMoveSource | null` | Where it moves from, once the moving agent says. |
| `arrived` | `AgentMoveArrived` | What arrived so far, for the "Found on your laptop" list. |
| `steps` | `AgentMoveStep[]` | The finish's progress, in order. |
| `landsAs` | `JsonObject | null` | Where it lands (the moving side): the agent's `name` and `harness`, and `cwd`, where its session moves to. |
| `question` | `string | null` | What a finish asks before it makes anything (a session that carried no MCP server and no skill: none?). |
| `endpoints` | `string[]` | The move's calls (the moving side), one line each: method, path and what it does. |
| `agentId` | `string | null` | The agent it made, once `done`. |
| `conversation` | `string | null` | The agent's conversation holding the moved session, once `done`. |
| `error` | `string | null` | Why it failed. |
| `expiresAt` | `Date | null` | When it ends if nobody finishes it. |
| `createdAt` | `Date | null` |  |

Types:

```typescript
/** `waiting` (its code unused), `moving` (things arriving), `finishing`, `done`, `failed` (finish again), `canceled`, `expired`. */
type AgentMoveStatus = "waiting" | "moving" | "finishing" | "done" | "failed" | "canceled" | "expired";

type JsonObject = { [key: string]: unknown };

/** Where the session moves from, as the moving agent says. */
interface AgentMoveSource {
  harness: string;
  host: string;
  cwd: string;
  cliVersion: string | null;
  sessionId: string | null;
  title: string | null;
}

/** What arrived so far: names, sizes and counts, never a value. */
interface AgentMoveArrived {
  session: { harness: string; sessionId: string | null; title: string | null; messages: number; toolCalls: number } | null;
  repo: { repoId: string; name: string; branch: string } | null;
  files: { path: string; sizeBytes: number }[];
  /** The secrets the person said yes to carrying: each by name, what it is and where it goes, never a value. */
  consent: { name: string; kind: string; to: string }[];
  /** Each secret carried, by name, and where it goes in the copy: `{env}`, `{file, mode}`, `{model}` or `{}`. */
  secrets: { name: string; to: JsonObject }[];
  setup: string[];
  checkout: { url: string; branch: string; path: string; secret: string | null; username: string | null } | null;
  /** Each tool server carried; `needsSignIn` when its login lived in a browser and the person signs in to it here. */
  mcpServers: { name: string; url: string; transport: string; headers: { name: string; secret?: string }[]; needsSignIn: boolean }[];
  skills: { name: string; files: number }[];
  memories: { name: string; description: string }[];
  note: { chars: number } | null;
  instructions: { chars: number } | null;
  /** Once finished: what it made the account's of each secret, model key and tool server login, never a value. */
  carried: JsonObject[];
}

/** One step of the finish, in order: `secrets`, `agent`, `space`, `files`, `tools`, `skills`, `memories`, `conversation`. */
interface AgentMoveStep {
  name: "secrets" | "agent" | "space" | "files" | "tools" | "skills" | "memories" | "conversation";
  label: string;
  status: "running" | "done" | "failed";
  detail?: string;
  error?: string;
}
```

### AgentMove.create

```typescript
static create(options?: AgentMoveCreateOptions): Promise<AgentMove>
```

Make a move: a one-time code, good once for 30 minutes, and the prompt a person pastes into the coding-agent
session they want moved. The agent there carries what its work needs and finishes the move, which makes the agent.

Parameters:

- `options.name` (`string`): Its name; omitted, the moving agent's choice, else its folder's.
- `options.harness` (`string`): `claude_code`, `codex`, `opencode`, `hermes` or `openclaw`; omitted, the session's own.
- `options.model` (`string`): Its model in the harness's format; omitted, the session's or the harness's default.
- `options.modelConnection` (`string | ApiObject`): The connection holding its model's key or plan; omitted, the account's own that runs it.
- `options.user` (`UserOption`, default: the current user): `undefined` = the ambient user (`asUser`), `null` = the account itself.
- `options.client` (`NoClick`): The client to send with; defaults to the module client built from `NOCLICK_API_KEY`.
- `options.workspaceId` (`string`): The space (workspace) the agent joins.

Returns: The move, with `code` and `prompt` (only here).

Types:

```typescript
/** `undefined` = the ambient user (from `asUser`), `null` = the account itself. */
type UserOption = UserRef | null | undefined;

/** A `User` or your own id for the user. */
type UserRef = string | UserLike;

/** Anything that can name a user lazily (a `User`). */
interface UserLike {
  _userId(): Promise<string>;
}
```

### AgentMove.fromId

```typescript
static fromId(moveId: string, options?: CallOptions): AgentMove
```

A lazy reference to a move by id.

Parameters:

- `moveId` (`string`, required)
- `options.client` (`NoClick`): The client to send with; defaults to the module client built from `NOCLICK_API_KEY`.
- `options.user` (`UserOption`, default: the current user): `undefined` = the ambient user (`asUser`), `null` = the account itself.

Returns: A move that loads the first time you read a field. Nothing is sent yet.

Types:

```typescript
/** `undefined` = the ambient user (from `asUser`), `null` = the account itself. */
type UserOption = UserRef | null | undefined;

/** A `User` or your own id for the user. */
type UserRef = string | UserLike;

/** Anything that can name a user lazily (a `User`). */
interface UserLike {
  _userId(): Promise<string>;
}
```

### AgentMove.cancel

```typescript
cancel(): Promise<this>
```

Call the move off: its key stops working and what arrived goes. A finished move's agent stays.

Returns: This move, `canceled`.

### AgentMove.connectSignIn

```typescript
connectSignIn(name: string, credentialId: string): Promise<this>
```

Give a tool server the move carried needing sign-in the person's sign-in to it: the `mcp_oauth` connection
NoClick's own MCP sign-in made for its URL. Its `carried` entry then no longer needs sign-in.

Parameters:

- `name` (`string`, required)
- `credentialId` (`string`, required)

Returns: This move, its `carried` entry for the server no longer needing sign-in.

### AgentMove.redeem

```typescript
static redeem(
  code: string,
  options?: { host?: string; client?: NoClick },
): Promise<string>
```

Redeem a move code for the move's own key, once: it reaches only this move, for an hour. Keep it out of anything
you print.

Parameters:

- `code` (`string`, required)
- `options.host` (`string`)
- `options.client` (`NoClick`)

Returns: The key: it reaches only this move, for an hour.

### AgentMove.current

```typescript
static current(options?: { client?: NoClick }): Promise<AgentMove>
```

The move a move's own key belongs to (the moving agent's side).

Parameters:

- `options.client` (`NoClick`): The client to send with; defaults to the module client built from `NOCLICK_API_KEY`.

Returns: The move, with `lands_as` and the limits.

### AgentMove.setSource

```typescript
setSource(
  source: {
    harness: string;
    host: string;
    cwd: string;
    cliVersion?: string;
    sessionId?: string;
    title?: string;
    model?: string;
  },
): Promise<this>
```

Say where the session moves from: its harness, machine and folder.

Parameters:

- `source` (`{ harness: string; host: string; cwd: string; cliVersion?: string; sessionId?: string; title?: string; model?: string }`, required)

Returns: This move.

### AgentMove.uploadSession

```typescript
uploadSession(
  data: Uint8Array,
  options: { harness: string; cwd: string; sessionId?: string },
): Promise<this>
```

The session's own files: a tar of paths relative to the harness's home (`~/.claude` for Claude Code).

Parameters:

- `data` (`Uint8Array`, required)
- `options.harness` (`string`, required)
- `options.cwd` (`string`, required)
- `options.sessionId` (`string`)

Returns: This move; `arrived["session"]` says what NoClick read.

### AgentMove.repo

```typescript
repo(options?: { name?: string; branch?: string }): Promise<JsonObject>
```

A NoClick repo for the code (made once) and a push `url`, good for 10 minutes: treat it as a secret.

Parameters:

- `options.name` (`string`)
- `options.branch` (`string`)

Returns: `repo_id`, `name`, `branch`, `path`, `url`, `expires_at` and `cwd`.

Types:

```typescript
type JsonObject = { [key: string]: unknown };
```

### AgentMove.putFile

```typescript
putFile(path: string, data: Uint8Array | string): Promise<this>
```

A file from outside the repo, placed at `/workspace/<path>` (up to 100 MB).

Parameters:

- `path` (`string`, required)
- `data` (`Uint8Array | string`, required)

Returns: This move.

### AgentMove.consent

```typescript
consent(
  secrets: { name: string; kind: string; to: string }[],
  options: { confirmed: boolean },
): Promise<this>
```

The secrets the person said yes to carrying, each `{name, kind, to}` as they read it (never a value);
`confirmed: true` once they said yes in the session. A secret is carried only once it's listed here.

Parameters:

- `secrets` (`{ name: string; kind: string; to: string }[]`, required)
- `options.confirmed` (`boolean`, required)

Returns: This move; `arrived["consent"]` lists them.

### AgentMove.putSecret

```typescript
putSecret(
  name: string,
  value: string,
  options?: { to?: JsonObject },
): Promise<this>
```

One secret the session uses, sealed as it lands, and where it goes in the copy: `{env: NAME}`,
`{file: path, mode?}`, `{model: provider}` (the model key it runs on), or none for one a tool server's header
or the checkout refers to by name.

Parameters:

- `name` (`string`, required)
- `value` (`string`, required)
- `options.to` (`JsonObject`)

Returns: This move; `arrived["secrets"]` names it, never its value.

Types:

```typescript
type JsonObject = { [key: string]: unknown };
```

### AgentMove.setSetup

```typescript
setSetup(commands: string[]): Promise<this>
```

What the copy's sandbox runs as it starts (after its secrets' files are written): the CLIs the session used.

Parameters:

- `commands` (`string[]`, required)

Returns: This move.

### AgentMove.setCheckout

```typescript
setCheckout(
  url: string,
  branch: string,
  options?: { path?: string; secret?: string; username?: string },
): Promise<this>
```

The session's own git remote, checked out in the copy at the branch it pushed its work to.

Parameters:

- `url` (`string`, required)
- `branch` (`string`, required)
- `options.path` (`string`)
- `options.secret` (`string`)
- `options.username` (`string`)

Returns: This move; `lands_as["cwd"]` is where it's checked out.

### AgentMove.planLink

```typescript
planLink(): Promise<JsonObject>
```

The person's one-tap sign-in to the plan the session's harness runs on: its tokens never move.

Returns: `{connection, integration, status, url, expires_at}`.

Types:

```typescript
type JsonObject = { [key: string]: unknown };
```

### AgentMove.addMcpServer

```typescript
addMcpServer(
  name: string,
  url: string,
  options?: { transport?: "http" | "sse"; headers?: Record<string, string | {
    secret: string }>; signIn?: "browser";
  },
): Promise<this>
```

A remote MCP server it used (a public https URL); the agent gets its tools. A header is text, or `{secret}`.
`signIn: "browser"` for one whose login lives in a browser (a claude.ai connector, an OAuth sign-in): it moves
with no headers and no login, and the person signs in to it once on NoClick.

Parameters:

- `name` (`string`, required)
- `url` (`string`, required)
- `options.transport` (`"http" | "sse"`, default `"http"`)
- `options.headers` (`Record<string, string | { secret: string }>`)
- `options.signIn` (`"browser"`)

Returns: This move.

### AgentMove.addSkill

```typescript
addSkill(name: string, data: Uint8Array): Promise<this>
```

A skill: its folder as a tar, SKILL.md at its top.

Parameters:

- `name` (`string`, required)
- `data` (`Uint8Array`, required)

Returns: This move.

### AgentMove.addMemory

```typescript
addMemory(
  name: string,
  content: string,
  options: { description: string },
): Promise<this>
```

Something it learned, kept in its NoClick memory.

Parameters:

- `name` (`string`, required)
- `content` (`string`, required)
- `options.description` (`string`, required)

Returns: This move.

### AgentMove.setNote

```typescript
setNote(text: string): Promise<this>
```

The handoff note: what it's in the middle of and what's next. The agent reads it first.

Parameters:

- `text` (`string`, required)

Returns: This move.

### AgentMove.setInstructions

```typescript
setInstructions(text: string): Promise<this>
```

Its instructions: what it was told for every project (a user-level CLAUDE.md or AGENTS.md).

Parameters:

- `text` (`string`, required)

Returns: This move.

### AgentMove.finish

```typescript
finish(
  options?: {
    name?: string;
    model?: string;
    modelConnection?: string;
    harness?: string;
    none?: ("mcp_servers" | "skills")[];
  },
): Promise<this>
```

Make the agent from what arrived (the moving agent's side, with the move's own key).

Parameters:

- `options.name` (`string`)
- `options.model` (`string`)
- `options.modelConnection` (`string`)
- `options.harness` (`string`)
- `options.none` (`("mcp_servers" | "skills")[]`)

Returns: This move: `done`, with `agent_id` and `conversation`; or still `moving` with a `question`.
