
How AxiOwl Creates New Agent Sessions
AxiOwl treats a new agent session as a provider-owned object that must be created, correlated, and saved before it becomes a reliable target. The important detail is that AxiOwl does not pretend every provider has the same create API. It exposes one user-facing create surface, then hands the request to the selected provider edge and records exactly what that edge could prove.
In the current C++ implementation, creation starts either from the CLI command:
axiowl create --provider <provider> --name <agent> [--body <message> | --stdin] [--model <model>] [--cwd <cwd>]
or from the MCP tool:
axiowl_create_agent
Both paths end up in the same create pipeline. The difference is how sender identity is supplied when the first message body exists.
Sources read
README.mddocs/developer/README.mddocs/reference/architecture-overview.mddocs/reference/provider-support-matrix.mddocs/PLAN-SIMPLE-AXIOWL-APP-ARCHITECTURE.mdapps/windows-desktop/src/models.hppapps/windows-desktop/src/cli.cppapps/windows-desktop/src/mcp_server.cppapps/windows-desktop/src/create_lifecycle.hppapps/windows-desktop/src/create_lifecycle.cppapps/windows-desktop/src/app_paths.cppapps/windows-desktop/src/provider_edges.cppapps/windows-desktop/src/provider_modules.hppapps/windows-desktop/src/provider_codex.cppapps/windows-desktop/src/provider_claude.cppapps/windows-desktop/src/provider_copilot_cli.cppapps/windows-desktop/src/provider_opencode_cli.cppapps/windows-desktop/src/provider_cursor.cppapps/windows-desktop/src/provider_cursor_cli.cppapps/windows-desktop/src/provider_antigravity.cppapps/windows-desktop/src/provider_antigravity_cli.cppapps/windows-desktop/src/provider_vscode_native.cppapps/windows-desktop/src/provider_vscode_copilot.cppapps/windows-desktop/extensions/vscode-native/out/extension.jsapps/windows-desktop/extensions/vscode-copilot/out/extension.jsapps/windows-desktop/tests/mcp_conformance.ps1apps/windows-desktop/tests/vscode_native_provider_tests.cppapps/windows-desktop/tests/core_tests.cpp
The create request is small on purpose
The core create model is defined in CreateRequest. It carries a request id, provider, display name, initial message, model, and working directory. The result model is similarly explicit: provider, state, accepted flag, method used, evidence, error, requested display name, provider display name, provider session id, correlation state, rename recommendation, and the registry agent row.
That shape matters because AxiOwl has to separate three different ideas:
- The requested human name, such as
Research Agent. - The provider title, if the provider returns or later exposes one.
- The provider session id, which is the stable thing provider adapters use for later sends.
The registry row is not allowed to become sendable merely because a friendly name exists. The architecture docs say the registry maps agent name -> provider -> provider session id -> node, and the code follows that rule during create enrollment.
CLI create validates the first message before dispatch
run_create in cli.cpp parses --provider, --name, optional --body, optional --stdin, optional --model, and optional --cwd. It canonicalizes provider names before dispatch. For example, the CLI help accepts names such as codex-cli, vscode-native, and claude-code-cli, while the provider edge works with canonical values such as codex_cli, vscode_native, and claude_code_cli.
If there is no provider or no name, create fails before touching a provider.
If there is an initial message, AxiOwl treats it carefully. For normal CLI create, it requires a sender identity through --from and --from-node, or through a registry-resolved explicit sender. It then builds the same final visible AxiOwl body used for message sends and validates that body through the delivery worker preflight before provider dispatch. That keeps the first message from becoming an anonymous raw prompt that cannot route a reply.
There is one explicit exception in the current code: antigravity_cli create logs the first body under a raw provider-create prompt policy. The code records that as create_initial_body_raw, including original and final byte counts, instead of silently pretending it used the ordinary final-body path.
MCP create supplies the sender identity
The MCP tool implementation in mcp_server.cpp exposes axiowl_create_agent with provider, name, optional body, optional model, and optional cwd.
When an MCP caller supplies a body, the server resolves the host identity first. If there is no usable host session id, it throws a loud metadata error instead of asking the chat to invent a session. If identity exists, the MCP handler registers the sender and then calls the CLI create path with --stdin, --from, and --from-node.
That makes MCP create the preferred path for provider-hosted tests. The provider host already has the MCP session metadata AxiOwl needs, so AxiOwl can create the new provider session with a reply route already embedded in the first visible message.
The MCP conformance test checks that axiowl_create_agent is present alongside axiowl_whoami, axiowl_send_message, and axiowl_version.
Every create is logged as a lifecycle
Create has its own lifecycle log. app_paths.cpp places it under the AxiOwl state root as:
logs/create-lifecycle.jsonl
On Windows, the state root is under %LOCALAPPDATA%\AxiOwl. On Linux-style environments, it uses $XDG_STATE_HOME/axiowl or ~/.axiowl.
create_lifecycle.cpp records a stable set of fields for every create event: request id, provider, local node id, requested name, a hash of the first message, and status. For results, it adds accepted state, method used, provider session id, provider title, registry display name, correlation state, rename recommendation, evidence, and error.
The first message body itself is not written into this lifecycle record. The lifecycle stores a FNV-style hash, which lets operators correlate attempts without dumping the prompt into every create log entry.
Provider dispatch is explicit
After validation, create_with_provider in provider_edges.cpp selects the provider create edge. Current create dispatch includes:
codexcodex_cliantigravityantigravity_clivscode_nativevscode_copilot_backedcursorcursor_cliclaude_code_clicopilot_cliopencode_cli
That dispatch table does not mean all of those surfaces are equally supported. It means AxiOwl has a code path that can return an honest result for each of those provider names. Unknown providers return unknown_provider_create. remote returns remote_provider_create_not_implemented because remote create requires a separate remote node and provider contract.
The provider support matrix is stricter than the dispatch table. It marks several CLI surfaces as target, not fully supported, because final support requires response-backed proof and provider-owned MCP sender metadata.
Codex can create an empty thread, then optionally send the first turn
Codex is the clearest example of a provider with a real create primitive. The Codex create path starts a thread through the app-server protocol. On Windows, it launches the Codex app-server process and sends initialize, initialized, and thread/start. On the CLI path, it shells through codex app-server with the same thread-start idea.
If a model or working directory is provided, those are included in the thread start parameters. If a display name is requested, AxiOwl follows up with thread/name/set.
If an initial message exists, Codex gets an initial turn after the thread exists. The Windows path uses turn/start and observes for an agent message or turn completion. The CLI path writes the message to a temporary file and resumes the new thread with codex exec resume.
The saved provider session id is the Codex thread id. If the name set fails but the thread exists, AxiOwl still accepts the create as a created session, records the warning evidence, and marks rename_recommended when a requested name was not actually accepted by the provider.
CLI providers usually require a first prompt
Several CLI providers do not have a clean "make an empty chat" contract in the current implementation. Their create functions require an initial message because the first prompt is what causes the provider to create durable session state.
Claude Code CLI create uses claude -p --output-format json --session-id <uuid> with an MCP config and allowed AxiOwl tools. If Claude returns a session id, AxiOwl uses it; otherwise it falls back to the requested UUID. It saves session ids as claude_code_cli:session:<id>.
Copilot CLI create first checks that the Copilot CLI metadata patch is healthy. It then generates a UUID and runs the same send-like command flow used for Copilot CLI delivery. The saved id is copilot_cli:session:<uuid>, and the correlation state is requested_session_id.
OpenCode CLI create runs opencode run --format json --title <name> --dir <cwd> <message>. It accepts creation only when output includes a session id, saved as opencode_cli:session:<id>.
Cursor CLI create uses cursor-agent create-chat, requires an initial prompt, writes an MCP config for the created session workspace, sends the prompt, and records cursor_cli:session:<id> only after the session id is returned and the prompt succeeds.
Antigravity CLI create uses agy --new-project --print <message> in a valid working directory. It then correlates the newest conversation for that cwd and stores it as antigravity_cli:conversation:<id>. It rewrites the Antigravity CLI MCP config with the correlated conversation id after creation.
These are provider-edge behaviors, not generic AxiOwl behavior. If the executable is missing, cwd is invalid, auth is blocked, or the provider command does not return a stable id, AxiOwl reports that at the edge.
IDE-backed providers create through bridges
For VS Code native and VS Code Copilot-backed sessions, AxiOwl uses bridge extensions rather than pretending the CLI owns VS Code internals.
The C++ provider edge writes a command file under an AxiOwl bridge registry directory, ensures the bridge is active, opens a vscode://.../execute?command_id=<id> URI, and waits for a result file. The command includes the operation, target name, first message, timeout, provider, and any model preference.
The VS Code native bridge handles start_new_native_chat by running this command sequence:
workbench.action.chat.newChat -> workbench.action.chat.open -> workbench.action.chat.submit
It snapshots native chat sessions before and after the command and returns vscode_native:session:<id> when it can detect the new session.
The VS Code Copilot-backed bridge handles start_copilot_cli_session by using the Copilot CLI new-session sidebar command when the host exposes it, then opens and submits the first prompt. It returns copilot_cli:session:<id> when the new Copilot-backed session is detected.
Both bridge paths require a non-empty initial message. Both can accept the UI command while still failing correlation. The provider edge only enrolls a sendable session when it has a returned or discovered provider session id.
There is a test for one important negative path: VS Code native create must fail fast when only the old legacy bridge registry exists. It must not write a command file if no active native bridge is available.
Cursor and Antigravity desktop create by correlation
The Cursor desktop bridge creates a new composer through its bridge command path, then compares composer inventory before and after creation. If exactly one new composer appears, AxiOwl saves that composer id as the provider session. If inventory is unavailable or correlation is ambiguous, AxiOwl does not invent a sendable row.
The Antigravity desktop path uses the language server agentapi new-conversation command. It derives the live Agent API endpoint from Antigravity logs, reads the project id from Antigravity app storage, sends the initial prompt, and then correlates either a returned conversation id or a single newly discovered row. On non-Windows builds, the Antigravity desktop provider returns a clear not-supported-on-remote-Linux result.
Registry enrollment happens only after provider acceptance
Once a provider create result is accepted, enroll_created_agent decides whether a registry row can be saved.
If the provider accepted the request but did not return a stable provider session id, AxiOwl records create_pending_no_session and prints that no sendable registry row was created. That is a deliberate safety boundary.
If a session id exists, AxiOwl builds or merges an AgentRecord:
providercomes from the create result or request.provider_session_idis the stable session key.node_iddefaults tolocal.sendableis set true.sourcerecords the create method.- aliases include the requested name, provider title when known, full provider session id, and the suffix after
:session:when present.
If a row for the same provider/session/node already exists, AxiOwl merges into that row instead of duplicating it. If the provider title is unknown, the temporary display name becomes a visible pending name such as <provider> pending <session suffix> rather than a fake provider title.
The practical value
This design gives operators a useful rule of thumb: creation is successful only when the provider edge can prove enough to route the next message. A process exit code is not enough. A friendly name is not enough. A browser or editor command being accepted is not enough. AxiOwl wants the provider session id and records how it got it.
That is why create results include correlation_state, method_used, evidence, and rename_recommended. These fields turn "new chat failed" into a diagnosable event: missing executable, missing cwd, unhealthy patch, missing bridge, provider rejected command, missing created session id, ambiguous correlation, or provider accepted the session but did not accept the title.
The same rule also protects future sends. Once the registry has a sendable row, the provider adapter can target the real provider session id instead of guessing from a display name.
Closing
AxiOwl creates new agent sessions by keeping the center small and pushing provider-specific behavior to the edge. The CLI and MCP tool share one request shape. The lifecycle log records the attempt. The dispatch table selects a provider create function. The provider edge does whatever that provider actually supports. The registry enrolls only stable, sendable sessions.
That is the difference between "start something and hope" and a usable agent session: AxiOwl does not just launch a provider surface. It creates, correlates, records, and names the session in a way the next AxiOwl message can use.
Image prompt:
Create a polished graphic image related to: AxiOwl creating a new agent session through provider-specific create edges.
Subject: a central metallic command router module projecting a newly formed glowing session token into several distinct cable ports, with small status lights and clean technical components, no readable labels.
Style: halfway between a clean symbolic icon and a realistic product/technical illustration; professional SaaS/technical marketing style; crisp edges; high detail; no text; no logos.
Background: solid #00ff00 chroma key green screen background covering the full canvas edge to edge.
Restrictions: no owl, no axolotl, no birds, no animals, no mascot, no text, no watermark.