# WaveAssist > The deterministic agent runtime. Your coding agent authors a pipeline over MCP; > WaveAssist runs it on a schedule, deterministically. Intelligence is contained to > wrapped, schema-locked model calls (call_llm + a Pydantic response_model), so every > run returns the same structure. Pay a fraction of a cent per run. ## Connect (MCP) - Endpoint: https://mcp.waveassist.ai/mcp - Auth header: Authorization: Bearer YOUR_TOKEN - Get your rotatable MCP token from the Connect MCP panel at https://app.waveassist.io - $2 of runtime credit comes with every account. ## Install pip install waveassist ## Determinism model - The pipeline is plain Python: fetch, transform, post, persist, schedule. - Model calls go through call_llm(model, prompt, response_model). response_model is a Pydantic class, so output is a typed, schema-locked instance. Content can vary, structure never drifts. - fetch_data / store_data carry state between runs. - Every deploy does a real verify run on live infrastructure and arms the schedule only after it passes. is_test_run() is True during that verify run. ## API init(token=None, project_key=None, environment_key=None, run_id=None, check_credits=False) -> None Initialize the runtime. Resolves from args, env vars, or .env. Call once per node. store_data(key, data, run_based=False, data_type=None) Persist a value. data_type is "string" | "json" | "dataframe" (inferred if omitted). run_based=True scopes the value to the current run. fetch_data(key, run_based=False, default=None) Read a stored value, or default if absent. call_llm(model, prompt, response_model, should_retry=False, **kwargs) -> T Wrapped model call. response_model is a Pydantic BaseModel subclass; returns an instance of it. This is what makes output deterministic in shape. send_email(subject, html_content, attachment_file=None, cc=None, bcc=None, raise_on_failure=True) -> bool Send an HTML email from the agent. publish_dashboard(html_content, data_key="dashboard_html", run_based=False) -> str | None Store an HTML dashboard, return a public shareable URL. check_credits_and_notify(required_credits: float, assistant_name: str) -> bool Verify enough runtime credit before costly work; notify owner if not. fetch_openrouter_credits() -> dict Current project credit balance. mark_run_idle() -> bool Flag the current run as idle (executed but did no meaningful work). Dashboard collapses idle runs into a heartbeat. Absence of the flag means the run did work. is_test_run() -> bool True during a dry/verify run, before the schedule arms. Guard side effects with it. set_worker_defaults(token=None, project_key=None, environment_key=None, run_id=None) -> None set_default_environment_key(key: str) -> None ## Minimal agent from pydantic import BaseModel import waveassist waveassist.init() class Review(BaseModel): summary: str risk: str comments: list[str] def run(): pr = waveassist.fetch_data("pull_request") review = waveassist.call_llm( model="anthropic/claude-haiku-4.5", prompt=review_prompt(pr), response_model=Review, ) post_comment(pr, review) waveassist.store_data("last_review", review, data_type="json")