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:

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.

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()
class AgentMove

A move from a laptop: waiting for its code to be redeemed, moving while what the agent carries arrives (arrived), finishing while the agent is made (steps), then done with agent_id and conversation; failed (finish again), canceled or expired.

Attributes
idstr
statusstr

One of waiting, moving, finishing, done, failed, canceled, expired.

codestr | None

The one-time code (from create only): it works once, for 30 minutes.

promptstr | None

What a person pastes into the session to move (from create only): the guide and the code.

guide_urlstr

The guide the moving agent follows.

workspace_idstr | None

The space the agent joins.

draftdict[str, Any]

What the move was made with: name, harness, model, model_connection.

sourcedict[str, Any] | None

Where it moves from, as the moving agent says: harness, host, cwd, cli_version, session_id, title.

arriveddict[str, Any]

What arrived so far: session, repo or checkout, files, consent, secrets (names and where each goes), setup, mcp_servers, skills, memories, note, instructions, plan, and once finished carried; never a value.

stepslist[dict[str, Any]]

The finish's progress, in order: each name (agent, space, files, tools, skills, memories, conversation), label, status (running, done, failed), detail and error.

lands_asdict[str, Any] | None

Where it lands (on the moving side): the agent's name and harness, and cwd, the working directory its session moves to.

questionstr | None

What a finish asks before it makes anything (a session that carried no MCP server and no skill: does it have none?).

endpointslist[str] | None

The move's calls (on the moving side), one line each: method, path and what it does.

agent_idstr | None

The agent it made, once done.

conversationstr | None

The agent's conversation holding the moved session.

errorstr | None

Why it failed.

expires_atAny

When it ends if nobody finishes it.

created_atAny

createclassmethodasync

noclick.AgentMove.create(
    *, workspace=None, name=None, harness=None, model=None, model_connection=None,
    user=..., client=None
) -> 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 follows the guide the prompt names, carries what its work needs, and finishes the move, which makes the agent.

Args: workspace: The space (a Workspace or its id) the agent joins. name: Its name; omitted, the moving agent's choice, else its folder's. harness: claude_code, codex, opencode, hermes or openclaw; omitted, the session's own. model: Its model in the harness's format; omitted, the session's or the harness's default. model_connection: The connection holding its model's key or plan; omitted, the account's own that runs it.

Parameters
workspaceAnydefault None
namestr | Nonedefault None
harnessstr | Nonedefault None
modelstr | Nonedefault None
model_connectionAnydefault None
userAny

Who the call acts for. Defaults to the user set by noclick.as_user (none: the account itself).

(defaults to the current user)
clientClient | None

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

(default None)
Returns
AgentMove

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

Usage
move = noclick.AgentMove.create(name="Docs fixer", harness="claude_code")
print(move.prompt)

from_idclassmethod

noclick.AgentMove.from_id(move_id, *, client=None, user=...) -> AgentMove

A lazy reference to a move by id.

Parameters
move_idstrrequired
clientClient | None

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

(default None)
userAny

Who the call acts for. Defaults to the user set by noclick.as_user (none: the account itself).

(defaults to the current user)
Returns
AgentMove

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

Usage
move = noclick.AgentMove.from_id("8c1f3e2a-4b5d-4e6f-9a7b-0c1d2e3f4a5b")
print(move.status)

cancelasync

agent_move.cancel() -> AgentMove

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

Returns
AgentMove

This move, canceled.

Usage
noclick.AgentMove.from_id("8c1f3e2a-4b5d-4e6f-9a7b-0c1d2e3f4a5b").cancel()

connect_sign_inasync

agent_move.connect_sign_in(name, credential) -> AgentMove

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.

Parameters
namestrrequired
credentialAnyrequired
Returns
AgentMove

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

Usage
noclick.AgentMove.from_id("8c1f3e2a-4b5d-4e6f-9a7b-0c1d2e3f4a5b").connect_sign_in("notion", "cr_1")

redeemstatic

noclick.AgentMove.redeem(code, *, host=None, base_url=None) -> str

Redeem a move code for the move's own key, once. Keep it out of anything you print or save in your transcript: write it to a file only you read.

Parameters
codestrrequired
hoststr | Nonedefault None
base_urlstr | Nonedefault None
Returns
str

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

Usage
key = noclick.AgentMove.redeem("nc_move_...", host="ana-mbp")

currentclassmethodasync

noclick.AgentMove.current(*, client=None) -> AgentMove

The move the client's key belongs to (a move's own key, from redeem).

Parameters
clientClient | None

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

(default None)
Returns
AgentMove

The move, with lands_as and the limits.

Usage
moving = noclick.AgentMove.current(client=noclick.Client(api_key=key))
print(moving.lands_as["cwd"])

set_sourceasync

agent_move.set_source(
    *, harness, host, cwd, cli_version=None, session_id=None, title=None, model=None
) -> AgentMove

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

Parameters
harnessstrrequired
hoststrrequired
cwdstrrequired
cli_versionstr | Nonedefault None
session_idstr | Nonedefault None
titlestr | Nonedefault None
modelstr | Nonedefault None
Returns
AgentMove

This move.

Usage
moving.set_source(harness="claude_code", host="ana-mbp", cwd="/Users/ana/code/acme")

upload_sessionasync

agent_move.upload_session(data, *, harness, cwd, session_id=None) -> AgentMove

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

Parameters
databytesrequired
harnessstrrequired
cwdstrrequired
session_idstr | Nonedefault None
Returns
AgentMove

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

Usage
moving.upload_session(tar_bytes, harness="claude_code", cwd="/Users/ana/code/acme", session_id=sid)

repoasync

agent_move.repo(*, name=None, branch=None) -> dict[str, Any]

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

Parameters
namestr | Nonedefault None
branchstr | Nonedefault None
Returns
dict[str, Any]

repo_id, name, branch, path, url, expires_at and cwd.

Usage
pushed = moving.repo()
# git push <pushed["url"]> HEAD:refs/heads/<pushed["branch"]>

put_fileasync

agent_move.put_file(path, data) -> AgentMove

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

Parameters
pathstrrequired
databytesrequired
Returns
AgentMove

This move.

Usage
moving.put_file("notes/spec.md", open("/Users/ana/notes/spec.md", "rb").read())

consentasync

agent_move.consent(secrets, *, confirmed) -> AgentMove

The secrets the person said yes to carrying, each {name, kind, to} (what it is and where it goes, 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; this replaces the list sent before.

Parameters
secretslist[Mapping[str, str]]required
confirmedboolrequired
Returns
AgentMove

This move; arrived["consent"] lists them.

Usage
moving.consent([{"name": "linear-token", "kind": "Linear API key", "to": "env LINEAR_API_KEY"}],
               confirmed=True)

put_secretasync

agent_move.put_secret(name, value, *, to=None) -> AgentMove

One secret the session uses, sealed as it lands, and where it goes in the copy: {"env": NAME}, {"file": path, "mode": "600"}, {"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
namestrrequired
valuestrrequired
toMapping[str, Any] | Nonedefault None
Returns
AgentMove

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

Usage
moving.put_secret("linear-token", os.environ["LINEAR_API_KEY"], to={"env": "LINEAR_API_KEY"})

set_setupasync

agent_move.set_setup(commands) -> AgentMove

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

Parameters
commandslist[str]required
Returns
AgentMove

This move.

Usage
moving.set_setup(["npm install -g @linear/cli"])

set_checkoutasync

agent_move.set_checkout(
    url, branch, *, path=None, secret=None, username=None
) -> AgentMove

The session's own git remote (an https URL), checked out in the copy at branch (where the session pushed its work), signed in with the carried secret secret's value when it must be.

Parameters
urlstrrequired
branchstrrequired
pathstr | Nonedefault None
secretstr | Nonedefault None
usernamestr | Nonedefault None
Returns
AgentMove

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

Usage
moving.set_checkout("https://github.com/acme/web.git", "noclick/ana-mbp", secret="github-token")

add_mcp_serverasync

agent_move.add_mcp_server(
    name, url, *, transport='http', headers=None, sign_in=None
) -> AgentMove

A remote MCP server it used (a public https URL); the agent gets its tools. A header's value is text, or {"secret": name} for a carried secret's (a login written as text is refused).

Args: sign_in: "browser" for a server 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
namestrrequired
urlstrrequired
transportstrdefault 'http'
headersMapping[str, Any] | Nonedefault None
sign_instr | Nonedefault None
Returns
AgentMove

This move.

Usage
moving.add_mcp_server("deepwiki", "https://mcp.deepwiki.com/mcp")
moving.add_mcp_server("notion", "https://mcp.notion.com/mcp", sign_in="browser")

add_skillasync

agent_move.add_skill(name, data) -> AgentMove

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

Parameters
namestrrequired
databytesrequired
Returns
AgentMove

This move.

Usage
moving.add_skill("release-notes", tar_bytes)

add_memoryasync

agent_move.add_memory(name, content, *, description) -> AgentMove

Something it learned, kept in its NoClick memory.

Parameters
namestrrequired
contentstrrequired
descriptionstrrequired
Returns
AgentMove

This move.

Usage
moving.add_memory("deploy-steps", "Deploy with make ship.", description="How this repo deploys")

set_noteasync

agent_move.set_note(text) -> AgentMove

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

Parameters
textstrrequired
Returns
AgentMove

This move.

Usage
moving.set_note("Halfway through the retry fix; next, a test for the third retry.")

set_instructionsasync

agent_move.set_instructions(text) -> AgentMove

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

Parameters
textstrrequired
Returns
AgentMove

This move.

Usage
moving.set_instructions(open(os.path.expanduser("~/.claude/CLAUDE.md")).read())

finishasync

agent_move.finish(
    *, name=None, model=None, model_connection=None, harness=None, none=None
) -> AgentMove

Make the agent from what arrived, step by step, and end the move's key. Finish again after a failed step to pick up there.

Args: harness: The harness it runs on, when the Draft screen named none (a carried key the session's own harness doesn't run on is refused naming the ones it does). model: Its model, in that harness's format, when the Draft screen named none. none: What the session has none of (mcp_servers, skills), said outright: a finish that carried neither asks first (question).

Parameters
namestr | Nonedefault None
modelstr | Nonedefault None
model_connectionstr | Nonedefault None
harnessstr | Nonedefault None
noneSequence[str] | Nonedefault None
Returns
AgentMove

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

Usage
moving.finish()
moving.finish(harness="opencode", model="openrouter/anthropic/claude-sonnet-4.5")