Starting the dev server
Project detection
The CLI identifies Python projects by checking, in order:- AgentMark setup files:
agentmark_client.py,.agentmark/dev_server.py, or a rootdev_server.py. These are decisive: once you set up your project, an unrelated manifest file no longer overrides TypeScript/Python detection. (agentmark.client.tsis the equally decisive TypeScript marker.) - Python manifests:
pyproject.toml,requirements.txt, orsetup.py. These matter before any AgentMark files exist, so a fresh pip project gets Python guidance fromdoctoranddevon first contact.
Virtual environment detection
The CLI automatically detects and uses virtual environments:Entry point resolution
The CLI resolves the dev server entry point in this order:| Location | Description |
|---|---|
dev_server.py | Custom dev server (project root) |
.agentmark/dev_server.py | Standard entry point (created by you or your AI tool) |
dispatch method handles every job it receives (prompt-run, dataset-run, and get-evals, which lists the evals registered on your client).
Neutral client and runner
The entry point builds a webhook runner from three pieces and serves it. Keepagentmark_client.py minimal (loader, client, and your evals) and put the executor, tracing init, and runner in .agentmark/dev_server.py:
- Client (
agentmark_client.py):create_agentmark(loader=ApiLoader.local(base_url="http://localhost:9418")), plus your evals. - Executor + runner (
.agentmark/dev_server.py): write acreate_executorfor your SDK, thenrunner = create_webhook_runner(client, executor). The full executor contract and copy-paste handlers (object, streaming, every SDK) live on Connect your SDK. - Serve:
serve_webhook_runner(runner)(see Entry-point file).
agentmark_client.py + .agentmark/dev_server.py files, see Client setup.
Local tracing differs from production. The runner wires span hooks, but spans only export once you initialize tracing, and in local dev you point the exporter at the dev API server (unauthenticated, no cloud keys) so See Tracing setup for the production configuration.
agentmark doctor --smoke and the local trace UI see your runs:Entry-point file
The CLI boots.agentmark/dev_server.py (or dev_server.py at your project root) and passes --webhook-port / --api-server-port. It strips cloud credentials from the spawned environment, so a client that picks its loader by API-key presence (the client setup pattern) lands on the local loader; the example above pins ApiLoader.local directly, which behaves the same in local dev. The entry point must keep serving HTTP: serve_webhook_runner(runner) is the line that does that. It serves runner.dispatch, the same handler a managed deployment exposes as handler = runner.dispatch. Without it the process builds the runner, exits, and agentmark dev reports Webhook server stopped.
serve_webhook_runner is the Python counterpart of the TypeScript createWebhookServer (@agentmark-ai/cli/runner-server).
Environment variables
The CLI sets the following environment variables for the spawneddev_server.py:
| Variable | Value | Description |
|---|---|---|
AGENTMARK_DEV_SERVER | http://localhost:{api_port} | Local API server URL; the example entry point reads it to point the tracing exporter |
PYTHONPATH | project root (prepended) | Lets .agentmark/dev_server.py import project-root modules like agentmark_client |
PYTHONDONTWRITEBYTECODE | 1 | Prevents __pycache__ creation |
PYTHONUNBUFFERED | 1 | Ensures real-time output |
PYTHONPYCACHEPREFIX | per-run temp directory | Keeps stale bytecode from masking source edits between restarts |
AGENTMARK_API_KEY, AGENTMARK_APP_ID, and AGENTMARK_BASE_URL from the spawned process, so a client that picks its loader by API-key presence stays in local mode instead of loading deployed prompts from the Cloud.
Server architecture
When you runagentmark dev, three servers start:
- Receives prompt execution requests from the CLI
- Uses your
agentmark_client.pyconfiguration - Executes prompts through your executor, which calls your LLM SDK
- Returns streaming or non-streaming responses
Port configuration
Override default ports with CLI options:| Option | Default | Description |
|---|---|---|
--webhook-port | 9417 | Webhook server port |
--api-port | 9418 | API server port |
--app-port | 3000 | UI server port |
Wire contract
You normally never implement this;serve_webhook_runner(runner) is the whole server. The contract below is for custom entry points (your own framework, extra routes) and for debugging with curl.
Every job arrives as POST / with a JSON {type, data} body. Three event types exist:
prompt-run
Executes a single prompt:
dataset-run
Executes a prompt across a dataset:
get-evals
Control-plane job: lists the eval names registered on your client, which populates the Dashboard’s New Experiment dialog. Carries no AST; the response is a flat JSON body{"type": "evals", "result": [...names], "traceId": null}.
Responses
The CLI (run-prompt, run-experiment) and the Dashboard switch parsing on one response header:
- Streaming (
runner.dispatchreturned a result with astream): respond withAgentMark-Streaming: trueandContent-Type: application/x-ndjson, then write the stream’s NDJSON lines as they arrive (one JSON event per line:text/object/dataset/errorchunks). After the stream drains, append a final{"type": "done", "traceId": "..."}line when the result carries atraceId; that’s where the CLI reads the trace link from. - Non-streaming: respond
200with the dispatch result as a plain JSON body. - Errors: respond with a non-2xx status and a
{"message": "..."}JSON body (400 for malformed/unknown jobs, 500 for executor failures).
createWebhookServer) and the managed-deployment server implement; serve_webhook_runner keeps the Python side pinned to it.
Running prompts
With the dev server running, execute prompts from another terminal:Troubleshooting
agentmark doctor reports missing dependencies
agentmark doctor checks .venv/, then venv/, then the system pip, in that priority order, so it correctly finds packages installed inside a virtual environment. If you still see a missing-package warning after installing into your venv, confirm the venv pip resolves the packages:
Virtual environment not found
If you see “python not found” errors:Module not found
Confirm you installed dependencies in the correct virtual environment:Port already in use
If ports are busy, specify alternative ports:agentmark_client.py not found
The CLI requires agentmark_client.py in your project root:
Agent frameworks
An agent-framework executor works the same in the dev server. Your handler runs an agent loop instead of a single completion, but it’s still acreate_executor wired into the runner above. See Connect your SDK for the agent-loop executor, including streaming with tool-call events.
Next steps
Client setup
Python client, dev server, and deploy handler files
Connect your SDK
Wire any LLM SDK with an executor
Reference executors
Copy-paste executors for OpenAI, Anthropic, agent frameworks
Running prompts
Execute prompts from CLI
Have questions?
Reach out any time:
- Email the team at hello@agentmark.co for support
- Schedule an Enterprise Demo to learn about AgentMark’s business solutions