Metadata-Version: 2.4
Name: happy-engineering-sdk
Version: 0.1.0
Summary: Python SDK for controlling Happy agent sessions
Project-URL: Homepage, https://happy.engineering
Author-email: Scott Fraser <scott@jascro.com>
License: MIT
Keywords: agents,ai,engineering,happy,llm,sdk
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Requires-Dist: cryptography>=43.0
Requires-Dist: httpx>=0.27
Requires-Dist: pynacl>=1.5
Requires-Dist: python-socketio[asyncio]>=5.11
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Description-Content-Type: text/markdown

# happy-engineering-sdk

[![PyPI version](https://img.shields.io/pypi/v/happy-engineering-sdk)](https://pypi.org/project/happy-engineering-sdk/)
[![Python versions](https://img.shields.io/pypi/pyversions/happy-engineering-sdk)](https://pypi.org/project/happy-engineering-sdk/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

Python SDK for controlling Happy agent sessions.

## Installation

```bash
pip install happy-engineering-sdk
```

## Credentials

The SDK authenticates using a key file and a server URL.

**Key file** — download `agent.key` from the Happy dashboard and place it at:

```
~/.happy/agent.key
```

**Server URL** — set the `HAPPY_SERVER_URL` environment variable to your Happy
server's base URL:

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

## Quick start

The simplest usage is `run_task()` — it spawns a session, sends a prompt, waits
for the agent to finish, and stops the session, all in one call:

```python
import asyncio
from happy_sdk import HappyClient

async def main():
    client = HappyClient()
    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())
```

## Manual lifecycle

For finer control, manage the session lifecycle directly:

```python
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)
    await client.stop_session(session_id)

asyncio.run(main())
```

## API reference

All methods are `async` and must be called from an async context.

| Method | Signature | Description |
|--------|-----------|-------------|
| `run_task` | `(machine_id, directory, prompt, agent="claude", timeout_seconds=600)` | Spawn a session, send a prompt, wait for turn completion, and stop — returns the session ID |
| `spawn_session` | `(machine_id, directory, agent="claude", create_dir=False)` | Create a new agent session on the given machine in the given directory — returns the session ID |
| `send_message` | `(session_id, text, permission_mode="yolo")` | Send a message to an active session |
| `wait_for_turn_completion` | `(session_id, timeout_seconds=300)` | Block until the agent finishes its current turn |
| `stop_session` | `(session_id)` | Stop a running session |

## License

MIT — see [LICENSE](LICENSE).
