Skip to main content

Python SDK for controlling Happy agent sessions

Project description

happy-engineering-sdk

PyPI version Python versions License: MIT

Python SDK for controlling Happy agent sessions.

Installation

pip install happy-engineering-sdk

Credentials

The SDK supports three ways to supply credentials.

1. Environment variables (recommended for containers)

export HAPPY_SERVER_URL=https://api.happy.engineering
export HAPPY_TOKEN=eyJ...
export HAPPY_SECRET=DroKzo0w...==

HAPPY_TOKEN is the bearer token and HAPPY_SECRET is the raw base64 machineKey string from your access.key file.

2. Key file (default for local use)

Download access.key (or agent.key) from the Happy dashboard and place it at:

~/.happy/access.key   # written by the Happy CLI
~/.happy/agent.key    # legacy location

The SDK understands both formats — the CLI-written access.key format (encryption.machineKey) and the older agent.key format (secret).

Set the server URL:

export HAPPY_SERVER_URL=https://api.happy.engineering

3. Inline kwargs

client = HappyClient(
    server_url="https://api.happy.engineering",
    token="eyJ...",
    secret_b64="DroKzo0w...==",
)

Quick start — async (HappyClient)

import asyncio
from happy_sdk import HappyClient

async def main():
    client = HappyClient()          # reads ~/.happy/agent.key + HAPPY_SERVER_URL
    session_id = await client.run_task(
        machine_id="my-machine",
        directory="/home/user/project",
        prompt="Summarise this week's PRs",
    )
    print(f"Task complete — session {session_id}")

asyncio.run(main())

Using environment variables:

client = HappyClient.from_env()    # reads HAPPY_TOKEN, HAPPY_SECRET, HAPPY_SERVER_URL

Quick start — sync (SyncHappyClient)

For Django management commands, CLI scripts, or any sync context — use SyncHappyClient. It has the same API as HappyClient but wraps every call with asyncio.run() internally so you never touch async machinery:

from happy_sdk import SyncHappyClient

# From environment variables
client = SyncHappyClient.from_env()

session_id = client.run_task(
    machine_id="my-machine",
    directory="/home/user/project",
    prompt="Summarise this week's PRs",
)
print(f"Task complete — session {session_id}")

All three constructor styles work with SyncHappyClient:

# From env vars
client = SyncHappyClient.from_env()
client = SyncHappyClient.from_env(server_url="https://...")

# From inline kwargs
client = SyncHappyClient(server_url="...", token="...", secret_b64="...")

# From key file
client = SyncHappyClient(server_url="...", credentials_path="~/.happy/access.key")

Manual session lifecycle

import asyncio
from happy_sdk import HappyClient

async def main():
    client = HappyClient()

    session_id = await client.spawn_session(
        machine_id="my-machine",
        directory="/home/user/project",
    )
    await client.send_message(session_id, "Hello")
    await client.wait_for_turn_completion(session_id)
    messages = await client.get_messages(session_id)
    await client.stop_session(session_id)

asyncio.run(main())

API reference

HappyClient (async) / SyncHappyClient (sync)

Both classes expose identical method signatures. HappyClient methods are async; SyncHappyClient methods are regular (blocking) functions.

Constructors

Constructor Description
HappyClient(server_url=None, credentials_path=None, token=None, secret_b64=None) File or kwargs. token+secret_b64 take precedence over credentials_path. server_url falls back to HAPPY_SERVER_URL.
HappyClient.from_env(server_url=None) Reads HAPPY_TOKEN, HAPPY_SECRET, HAPPY_SERVER_URL. Raises AuthenticationError if any are missing.
SyncHappyClient(...) Same arguments as HappyClient.
SyncHappyClient.from_env(server_url=None) Same as HappyClient.from_env.

Session lifecycle

Method Signature Description
spawn_session (machine_id, directory, agent="claude", create_dir=False) → str Create a new agent session — returns the session ID
stop_session (session_id) Stop a running session
delete_session (session_id) Permanently delete a session

Messaging

Method Signature Description
send_message (session_id, text, permission_mode="yolo") Send a message to an active session

Waiting

Method Signature Description
wait_for_turn_completion (session_id, timeout_seconds=300) Block until the agent finishes its current turn
wait_for_idle (session_id, timeout_seconds=300) Block until the session enters an idle state

Query

Method Signature Description
list_sessions (active_only=False) → list[Session] List all (or only active) sessions
get_session (session_id) → Session Fetch a single session — raises SessionNotFound if it doesn't exist
is_alive (session_id) → bool Whether the session is currently active on the server
get_messages (session_id) → list[Message] Fetch all messages for a session
list_machines (active_only=False) → list[Machine] List all (or only active) machines
get_machine (machine_id) → Machine Fetch a single machine

Convenience

Method Signature Description
run_task (machine_id, directory, prompt, agent="claude", timeout_seconds=600) → str Spawn, send, wait, stop — returns session ID

Cleanup

Method Signature Description
close () Release any held resources (no-op in the current implementation)

Types

Type Fields
Session id: str, active: bool, created_at: int, metadata: dict, agent_state: str | None
Machine id: str, active: bool, metadata: dict
Message id: str, seq: int, content: dict, created_at: int
Agent Literal["claude"]
PermissionMode Literal["yolo"]

Exceptions

All exceptions inherit from HappyError.

Exception Raised when
AuthenticationError Credentials missing, expired, or malformed
MachineOfflineError Target machine is not connected to the server
SessionNotFound No session with the given id exists on the server
SpawnError Session spawn failed
TimeoutError Wait exceeded the specified timeout
EncryptionError Encrypt or decrypt operation failed
ConnectionError Socket connection failed or disconnected unexpectedly

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

happy_engineering_sdk-0.2.1.tar.gz (38.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

happy_engineering_sdk-0.2.1-py3-none-any.whl (13.8 kB view details)

Uploaded Python 3

File details

Details for the file happy_engineering_sdk-0.2.1.tar.gz.

File metadata

  • Download URL: happy_engineering_sdk-0.2.1.tar.gz
  • Upload date:
  • Size: 38.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for happy_engineering_sdk-0.2.1.tar.gz
Algorithm Hash digest
SHA256 53f31b09a4b7c1804b4d7e146e78cc14d553413513ef7d81a28681601b2307ca
MD5 34e5bef8f8a710e02ef5300ff5deab58
BLAKE2b-256 faf1da6085fa39aaecca3b7d8018ece1029dd6197ab5858ee2d93a31339c3af4

See more details on using hashes here.

File details

Details for the file happy_engineering_sdk-0.2.1-py3-none-any.whl.

File metadata

File hashes

Hashes for happy_engineering_sdk-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 37bb3c0ed0d6923700946eaddf685cfc0a8d40e23aecd880eb471f7f88b58cad
MD5 7cb79841b532c00dfeecf92e3b506a29
BLAKE2b-256 17335efcf4842033c048753989b5de99331d9394e4d338c48092f4aeeb2ff71b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page