Metadata-Version: 2.4
Name: cccc-sdk
Version: 0.4.55
Summary: Client SDK for the CCCC daemon (IPC v1)
License-Expression: Apache-2.0
Project-URL: Source, https://github.com/ChesterRa/cccc-sdk
Project-URL: Issues, https://github.com/ChesterRa/cccc-sdk/issues
Keywords: cccc,sdk,ipc,agents
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# CCCC Python SDK

This package is the **Python client SDK** for CCCC daemon (Daemon IPC v1).

0.4.55 adds Backlog sources to task helpers and aligns with the daemon's
Backlog, task and delivery contracts. Coordination-note helpers are removed;
callers must migrate. See the [0.4.55 migration guide](https://github.com/ChesterRa/cccc-sdk/blob/main/spec/SDK_0455_MIGRATION.md),
including direct upgrades from 0.4.47. The SDK adds no automatic retry.

## Relationship to CCCC core

- CCCC core repository: https://github.com/ChesterRa/cccc
- `cccc` core owns the native Rust daemon/web/CLI and runtime state under `CCCC_HOME`.
- `cccc-sdk` provides client APIs only and must connect to a running daemon.

It requires a running CCCC daemon. The SDK does **not** ship a daemon.

## Versioning

This SDK follows daemon contracts rather than strict daemon version strings:
- Use `assert_compatible(...)` with required capabilities/ops for runtime gating.
- Newer workflow helpers cover `tracked_send`, Context Ops v3 task/agent state operations, and capability discovery.

The current message contract is an intentional atomic cut. Upgrade the SDK and
daemon together; old attention/ACK fields are not mapped or silently downgraded.

`send` and `reply` also accept `suggested_user_message`: a visible proposed
next message for the human user. The daemon stores it as message metadata and
never sends it automatically.

Structured question answers, including V2 option-plus-note answers, use
`call("reply_request_answer", ...)`. Preserve the note and reuse the same
`client_id` if an outcome is uncertain. See the
[three-language examples](https://github.com/ChesterRa/cccc-sdk/blob/main/spec/SDK_0451_MIGRATION.md).

## Daemon endpoint discovery

The SDK connects to the daemon endpoint described by:

- `${CCCC_HOME}/daemon/ccccd.addr.json` (preferred, cross-platform), or
- `${CCCC_HOME}/daemon/ccccd.sock` (POSIX AF_UNIX fallback)

## Install

### Stable (PyPI)

```bash
pip install -U cccc-sdk
```

### RC preview (optional, TestPyPI first)

```bash
pip install -U --pre --index-url https://pypi.org/simple \
  --extra-index-url https://test.pypi.org/simple \
  cccc-sdk
```

### From source (development)

```bash
pip install -e .
```

## Usage

`message_history(..., sender=...)` requires CCCC 0.4.50 or later; older daemons
silently ignore the filter. `group_activity` reports review leads, not a measure
of member value; scheduled notices are not confirmed deliveries or model turns.

```bash
python - <<'PY'
from cccc_sdk import CCCCClient

c = CCCCClient()
c.assert_compatible(
    require_ipc_v=1,
    require_ops=["groups", "send", "reply", "tracked_send", "context_sync"],
)

groups = c.groups()
print(groups)
PY
```

Context Ops v3 helpers:

```python
c.coordination_brief_update(group_id="g_xxx", objective="Ship SDK updates", by="user")
c.task_move(group_id="g_xxx", task_id="t_xxx", status="done", by="user")
c.agent_state_update(group_id="g_xxx", actor_id="peer-impl", focus="testing", by="peer-impl")
```

Run a saved notification rule once without changing its schedule or run limit:

```python
c.group_automation_run_now(group_id="g_xxx", rule_id="standup", expected_version=7)
```

This creates real notifications and may wake members and use model credits.
The returned Actor IDs identify notices written to the ledger, not confirmed
deliveries. If the response is lost, the outcome may be unknown; do not
silently retry.

## Examples (repo)

This repository includes runnable examples under `python/examples/`:

```bash
python examples/compat_check.py
```

Stream events for a group:

```bash
python examples/stream.py --group g_xxx
```

Send a message:

```bash
python examples/send.py --group g_xxx --text "hello" --mode send
```

Message delivery uses one explicit mode:

```python
c.send(group_id="g_xxx", text="FYI", message_mode="mail")
c.send(group_id="g_xxx", text="Stop: wrong branch", message_mode="send")
c.send(
    group_id="g_xxx",
    text="Which option should we use?",
    message_mode="request_reply",
    to=["peer-1"],
)
messages = c.inbox_read(group_id="g_xxx", actor_id="peer-1", by="peer-1")
history = c.message_history(
    group_id="g_xxx",
    actor_id="peer-1",
    mode="send",
)
```

`mail` stores without an immediate runtime prompt, `send` performs a
best-effort immediate Push, and `request_reply` adds a concrete reply request.
`inbox_read` returns and consumes only Mail. Use the non-consuming
`message_history` helper when past Send, Send + Reply, or Mail traffic is needed.
Replies default to Send. Use `message_mode="mail"` for a non-urgent reply to
agent-only recipients; both modes fulfill the original reply request. Generic
ACK operations no longer exist.

Use `context_get(..., detail="overview" | "summary" | "full")` to control the
projection cost. `task_list` supports exact batches, filters, atomic status
pages, and pagination. Legacy `group_space_sync` is read-only status; use
explicit ingest/source operations for mutations.

Cross-group send:

```bash
python examples/send_cross_group.py --src g_src --dst g_dst --text "hello from src"
```

## Actor Profiles (global reusable runtime presets)

`cccc` supports global Actor Profiles so you can reuse runtime/command/env across groups.

```python
from cccc_sdk import CCCCClient

c = CCCCClient()

# list profiles
profiles = c.actor_profile_list()

# create or update a profile
profile = c.actor_profile_upsert(
    profile={
        "name": "Codex",
        "runtime": "codex",
        "command": ["codex"],
        "submit": "enter",
        "capability_defaults": {
            "autoload_capabilities": ["pack:space"],
            "default_scope": "actor",
        },
    }
)
profile_id = str((profile.get("profile") or {}).get("id") or "")

# create actor from profile
c.actor_add(group_id="g_xxx", actor_id="reviewer", profile_id=profile_id)

# profile secrets (write-only values)
c.actor_profile_secret_update(profile_id=profile_id, set={"OPENAI_API_KEY": "..."})
```

## Current high-value surfaces

```python
from cccc_sdk import CCCCClient

c = CCCCClient()

# Capability exposure for one caller scope
caps = c.capability_state(group_id="g_xxx", actor_id="foreman")

# Capability policy / allowlist overlay
policy = c.capability_allowlist_get()
preview = c.capability_allowlist_validate(
    mode="patch",
    patch={"defaults": {"source_level": {"skillsmp_remote": "indexed"}}},
)

# Group Space / Notebook status
space = c.group_space_status(group_id="g_xxx")

# Context v3: update the shared collaboration brief
c.coordination_brief_update(
    group_id="g_xxx",
    by="user",
    current_focus="Review the release candidate",
)
```

If you need an op that does not have a dedicated helper yet, use `call()` / `call_raw()`.

## Current native-daemon compatibility surface

```python
# Capture the bounded ANSI screen and exact raw cursor boundary.
snapshot = c.terminal_snapshot(
    group_id="g_xxx",
    actor_id="web-model",
    limit_bytes=512_000,
)

# Read or change the durable delivery mode for a Web Model actor.
preference = c.web_model_delivery_preferences_get(
    group_id="g_xxx",
    actor_id="web-model",
)
c.web_model_delivery_preferences_update(
    group_id="g_xxx",
    actor_id="web-model",
    mode="image_compat",
)

# Inspect a committed legacy turn without moving the actor cursor.
recovered = c.web_model_runtime_recover_turn(
    group_id="g_xxx",
    actor_id="web-model",
    event_ids=["e_xxx"],
)
```

`term_resize()` sends the standard `term_resize` operation. For older compatible
daemon builds that expose `terminal_resize`, the SDK falls back only
after receiving a structured `unknown_op`; transport failures are never
replayed, and the legacy result is normalized to the standard shape.
Auto-discovered clients re-read `ccccd.addr.json` when connection
establishment fails before any request bytes are sent. Explicit endpoints are
never replaced.

`capability_source_delete()` is deliberately source-scoped: the
current daemon does not implement instance-scoped deletion and callers should
not assume otherwise.

## CCCC 0.4.33 compatibility delta

```python
# Deliberately rotate provider session metadata for Claude, Codex and Grok.
c.actor_new_session(group_id="g_xxx", actor_id="reviewer")

# Page through retained PTY output by cursor.
page = c.terminal_history(
    group_id="g_xxx",
    actor_id="reviewer",
    before=None,
    limit_bytes=64_000,
)

# Large group copies use a daemon-local package path instead of base64 IPC.
exported = c.group_copy_export_file(group_id="g_xxx")
preview = c.group_copy_preview_import(package_path=exported["package_path"])
copied = c.group_copy_import(package_path=exported["package_path"])

# Manage the startup body delivered to the next fresh provider session.
c.group_preamble_set(
    group_id="g_xxx",
    content="This initialization is not a task. Wait for the targeted mission.\n",
)
preamble = c.group_preamble_get(group_id="g_xxx")
c.group_preamble_reset(group_id="g_xxx", confirm="preamble")

# Upload active-scope files and append one message with daemon-owned attachments.
c.send_files(
    group_id="g_xxx",
    paths=["reference.png", "candidate.png"],
    text="Inspect these files",
    to=["reviewer"],
)

# Current terminal operations.
recent = c.terminal_since(group_id="g_xxx", actor_id="reviewer", after=0)
c.term_resize(group_id="g_xxx", actor_id="reviewer", cols=120, rows=40)
```

A changed preamble applies on its next delivery; it is not reinjected into a
session that already received one. `group_reset` creates a new group id and
does not carry the override forward. If the preamble establishes a standby
boundary, wait until the actor returns to `waiting` or `idle` before sending
the authoritative mission. `send_files` accepts only regular files beneath
the group's active scope and validates every path before appending the message.

`events_stream` compatibility is verified by probing the operation itself;
the SDK does not rely only on the daemon's advertised capability flag.

`group_reset` is destructive: it creates a clean replacement and removes the
old group after copying selected configuration. The explicit confirmation must
equal the source group id:

```python
c.group_reset(group_id="g_xxx", confirm="g_xxx")
```

## CCCC 0.4.18 surface — Hermes runtime and Voice Secretary lease

```python
# Hermes runtime setup diagnostics and MCP preparation
status = c.runtime_hermes_status()
c.runtime_hermes_prepare(cwd=".", auto_enable_tools=True)
c.runtime_hermes_mcp_test(group_id="g_xxx", actor_id="hermes-1")

# Cross-tab Voice Secretary recording guard
lease = c.assistant_voice_recording_lease(
    group_id="g_xxx",
    action="acquire",
    owner_id="browser-tab-1",
    ttl_seconds=30,
)
```

## CCCC 0.4.17 surface — new op families

```python
from cccc_sdk import CCCCClient

c = CCCCClient()

# Tracked delegation — atomic task.create + send with idempotent replay
res = c.tracked_send(
    group_id="g_xxx",
    title="Fix login race",
    text="Please pick this up — see issue link",
    insight="The proposed fix may target the symptom rather than the ownership boundary.",
    to=["alice"],
    idempotency_key="fix-login-race-1",
    refs=[{"kind": "url", "url": "https://example.com/issue/42"}],
)
task_id = res["task_id"]

# Task list / per-task drill-down
tasks = c.task_list(group_id="g_xxx")
task = c.task_list(group_id="g_xxx", task_id=task_id)

# Structured refs on chat
c.send(
    group_id="g_xxx",
    text="Looking at the demo deck",
    insight="The deck may make the current option set look more settled than it is.",
    refs=[{"kind": "presentation_ref", "slot_id": "slot-1"}],
)

# Presentation workspace (slot-based viewer)
c.presentation_publish(
    group_id="g_xxx",
    slot="slot-1",
    title="Plan",
    card_type="markdown",
    content="# Sprint plan\n- ...",
)

# Voice Secretary state and instance-wide settings
state = c.assistant_state(group_id="g_xxx", assistant_id="voice_secretary")
settings = c.call("voice_secretary_settings_get", {})

# Copy a group for migration / backup
pkg = c.group_copy_export(group_id="g_xxx")
preview = c.group_copy_preview_import(package_b64=pkg["package_b64"])
new_group = c.group_copy_import(package_b64=pkg["package_b64"])

# Headless runtime control (Claude/Codex headless and beyond)
c.headless_set_status(group_id="g_xxx", actor_id="reviewer", status="working", task_id=task_id)

# Capability Center extensions
c.capability_visibility(group_id="g_xxx", capability_id="skill:foo", hidden=True, actor_id="reviewer", by="reviewer")
c.capability_install_target(group_id="g_xxx", target="github:owner/repo", actor_id="reviewer", scope="session", ttl_seconds=600)

# Operator-side: terminal tail, ledger snapshot, branding/observability
c.terminal_tail(group_id="g_xxx", actor_id="reviewer", max_chars=4000)
c.ledger_snapshot(group_id="g_xxx", reason="manual")
c.branding_update(patch={"product_name": "My CCCC"})
```

Use `call()` for intentionally low-level or newly added non-streaming ops that
do not yet have a dedicated helper. Duplex browser/VNC/PTY attach operations
remain outside this request/response client and require a separate streaming
transport contract. See `spec/ADAPTATION_PLAN.md` for the exact boundary.

## CCCC compatibility

All three SDK package versions target CCCC 0.4.55. `spec/core.json` pins the
reviewed core revision. See the
[0.4.47 migration guide](https://github.com/ChesterRa/cccc-sdk/blob/main/spec/SDK_0447_MIGRATION.md)
for exact message reads, Inbox summaries, removed Voice operations and daemon
version limitations. Matching version numbers do not replace capability checks.
For removed Group memory helpers, see the
[memory migration guide](https://github.com/ChesterRa/cccc-sdk/blob/main/spec/SDK_LOCAL_MEMORY_API.md).
If you upgrade directly from 0.4.47, `capability_search` also no longer accepts
the filters the daemon ignored; see
[Upgrading directly from 0.4.47](https://github.com/ChesterRa/cccc-sdk/blob/main/spec/SDK_0451_MIGRATION.md#upgrading-directly-from-0447).

Qualified Connect sends require a stable caller-owned retry key:

```python
client.connect_send(group_id="local", instance_id="remote-instance", target_group_id="remote-group",
                    client_id="retained-caller-key", text="Please review", message_mode="mail")
```

Use `connect_catalog` / `connectCatalog` to read authorized cached peers and
`connect_send_files` / `connectSendFiles` to send files from the daemon's project
scope. Accepted means queued locally, not confirmed delivery. Keep the same key
and body after an uncertain result; the SDK never automatically replays a send.
Connect replies use the local received event ID with the ordinary reply helper.

`context_sync(if_version=...)` / `contextSync({ ifVersion })` rejects stale
updates with `version_conflict`. Reload before deciding whether to reapply.
Terminal history accepts `render_before` / `renderBefore` alongside `before`.

Compatibility requirements that lack an advertised capability and an audited
safe probe now fail instead of being executed or silently skipped. Retired
Presentation browser and Voice model-install helpers fail locally with migration
guidance; their interactive replacement belongs to CCCC Web, not daemon IPC.

## Voice library and Web Models

Use `assistant_voice_document_library`, `assistant_voice_document_library_update`
and `assistant_voice_document_delete` for the stored Voice document library.
Updates organize folders/documents and restore archives; delete permanently
removes the Markdown file. Empty `root_order=[]` clears ordering and
`folder_id=""` moves a document to root. The daemon enforces all permissions.

`actor_add(runtime="grok_web_model", ...)` configures a Grok Bot Actor; `grok`
is the separate CLI runtime. CCCC Web sets up its Bot URL, native Webhook
Routine credentials and remote MCP connector. Grok delivery uses no CCCC-managed
browser login. ChatGPT `web_model` uses its separate browser path.
