Skip to content

Migration Guide

This guide covers migrating from the legacy 0.x SDKs (atheon_codex) to the new unified v1.0 architecture.


What Changed

The v1.0 release represents a fundamental shift in how Atheon integrates with your application, moving from a blocking, synchronous model to a high-performance background queue.

Old SDKs (0.x) New SDKs (1.x)
Paradigm Synchronous request/response Fire-and-forget, background queue
Latency impact Adds Atheon API round-trip to every response Zero — events are batched and sent in background
Main call create_atheon_unit() / createAtheonUnit() track(provider, model_name, input, output, ...)
What you get back unit_configs (frontend config blob) Tuple/Array: (interaction_id, prompt_hash, fingerprint)
Frontend element <atheon-container> <atheon-input> & <atheon-output>
Frontend attributes data-atheon="{stringified configs}" interaction-id="{id}" prompt-hash="{hash}" fingerprint="{fp}"
Streaming support ✓ via begin() / finish()
Tool tracking ✓ via tool decorator/wrapper
Sub-agent tracking ✓ via agent decorator/wrapper
Init style Class instantiation per call site init(api_key) once at startup

Step-by-Step Migration

1. Replace the import and initialisation

You no longer instantiate the client at every call site. You initialize it globally once at startup.

Before:

from atheon_codex import AtheonCodexClient
client = AtheonCodexClient(api_key=os.environ.get("ATHEON_API_KEY"))

After:

import atheon
# Call once at application startup
atheon.init(os.environ["ATHEON_API_KEY"])

Before:

import { AtheonCodexClient } from 'javascript-codex';
const client = new AtheonCodexClient({ apiKey: process.env.ATHEON_API_KEY });

After:

import * as atheon from '@atheon-inc/codex';
// Call once at application startup. Awaits the security handshake.
await atheon.init({ apiKey: process.env.ATHEON_API_KEY });

2. Replace create_unit with track()

This is the core change. The old call was synchronous and returned a frontend config blob. The new call enqueues the event immediately (non-blocking) and returns tracking IDs and hashes.

Before:

result = client.create_atheon_unit(
    AtheonUnitCreateModel(query=user_query, base_content=llm_response)
)
return {"tracking": result.get("unit_configs", [])}

After:

interaction_id, prompt_hash, fingerprint = atheon.track(
    provider="openai",          # new required field
    model_name="gpt-4o",        # new required field
    input=user_query,
    output=llm_response,
    tokens_input=response.usage.prompt_tokens,    # optional but recommended
    tokens_output=response.usage.completion_tokens,
    finish_reason=response.choices.finish_reason,
)

return {
    "reply": llm_response, 
    "interaction_id": str(interaction_id),
    "prompt_hash": prompt_hash,
    "fingerprint": fingerprint
}

Before:

const result = await client.createAtheonUnit({
    query: userQuery,
    baseContent: llmResponse
});
return { tracking: result.unitConfigs };

After:

const [interactionId, promptHash, fingerprint] = atheon.track({
    provider: "openai",         // new required field
    modelName: "gpt-4o",        // new required field
    input: userQuery,
    output: llmResponse,
    tokensInput: response.usage.prompt_tokens,
    tokensOutput: response.usage.completion_tokens,
    finishReason: response.choices.finish_reason,
});

return {
    reply: llmResponse, 
    interaction_id: interactionId,
    prompt_hash: promptHash,
    fingerprint: fingerprint
};

Key differences: - queryinput - base_contentoutput - provider and model_name are new required fields - Return tuple of interaction_id, prompt_hash and fingerprint instead of unit_configs


3. Update the Async Path (Python Only)

(Note: Because Node.js is inherently asynchronous, the TS/JS SDK uses a single unified API. Python users must use the specific async methods if running within async frameworks).

Before:

from atheon_codex import AsyncAtheonCodexClient
async_client = AsyncAtheonCodexClient(api_key=os.environ.get("ATHEON_API_KEY"))
result = await async_client.create_atheon_unit(payload)

After:

import atheon
# Init once (sync, not async)
atheon.async_init(os.environ["ATHEON_API_KEY"])

# In your route handler — no await needed, enqueues immediately
interaction_id, prompt_hash, fingerprint = atheon.async_track(
    provider="anthropic",
    model_name="claude-sonnet-4-5",
    input=user_query,
    output=llm_response,
)

4. Update the Frontend

Atheon now uses two declarative web components instead of one, and relies on specific IDs rather than a stringified config blob.

Before:

<atheon-container id="chat-bubble">
  <div id="content"></div>
</atheon-container>

<script>
  container.setAttribute('data-atheon', JSON.stringify(backendResponse.tracking));
</script>

After:

<atheon-input>
  <textarea></textarea>
  <button data-atheon-submit>Send</button>
</atheon-input>

<atheon-output id="chat-bubble">
  <div id="content"></div>
</atheon-output>

<script>
  container.setAttribute('interaction-id', backendResponse.interaction_id);
  container.setAttribute('prompt-hash', backendResponse.prompt_hash);
  container.setAttribute('fingerprint', backendResponse.fingerprint);
</script>

React example:

Before:

<atheon-container data-atheon={JSON.stringify(tracking)}>
  <Markdown>{llmResponse}</Markdown>
</atheon-container>

After:

<atheon-output 
    interaction-id={interactionId}
    prompt-hash={promptHash}
    fingerprint={fingerprint}
>
  <Markdown>{llmResponse}</Markdown>
</atheon-output>

5. Add shutdown (new requirement)

The 0.x SDKs were stateless per-call, so no cleanup was needed. The 1.x SDKs run a background queue thread that must be flushed before your process exits.

For Django, Flask or other sync frameworks, register it with atexit:

import atexit
import atheon

atheon.init(os.environ["ATHEON_API_KEY"])
atexit.register(atheon.shutdown) # Flush on exit

For FastAPI, Starlette or other async frameworks:

from contextlib import asynccontextmanager
import atheon

from someasyncframework import Framework

@asynccontextmanager
async def lifespan(app: Framework):
    atheon.async_init(os.environ["ATHEON_API_KEY"])
    yield
    await atheon.async_shutdown()

app = Framework(lifespan=lifespan)
import * as atheon from "@atheon-inc/codex";

async function main() {
    await atheon.init({ apiKey: process.env.ATHEON_API_KEY! });
    //...
    await atheon.shutdown();
}

main();