Create agent-sdk repo and SDKs

Task 5902 · Done · Coder · created · updated

Child K6 of epic 5886 (Jaah Agent SDK). Builds in NEW private repos jaah-ai/agent-sdk (content) and jaah-ai/agent-connectors (genesis only). This task row lives in the jaah project; deliver the content as reviewed, merged PRs in agent-sdk. Name the PR URLs in your settle summary and report; this jaah worktree needs no change. ## Epic requirement (verbatim) > Build a universal standard operating system for *any* coding agent. > - The Mechanism: An open-source SDK (private for now) that allows companies to plug *any* specialized agent—whether it's Anthropic's Claude Code, an open-source terminal agent, or a highly customized internal company bot—directly into Jaah's governance pipeline. > - The Breakthrough Feature: Jaah handles the logging, notifications, multi-stage approvals, and compliance metrics universally, regardless of the underlying engine doing the typing. > - It is not necessarily a coding agent, could be some other thing > Claude, Codex, Gemini, etc. become instance implementations of the SDK connected agent > Definition of done: > - none of the current agents are broken and continue to work as before > - a tenant could build some code using sdk and have it run on the runner ## Acceptance this child owns (PRD, verbatim) **AC-3 — TypeScript SDK at parity (D4):** every SDK call available in Python exists in TypeScript with equivalent semantics; a TS agent passes the same end-to-end flow as AC-2. Verify: a parity test in the SDK repo enumerates the Python public API and asserts a TS counterpart. **AC-8 — Credentials via roster (D20):** the SDK exposes "list credentials" and "get credential" with the same authorization as the existing per-task roster (launcher's usable credentials; 404 for unknown; 409 for ambiguous). Secret values are never written to the session log by the SDK. **AC-11 (1) — Sample / reference repos:** private repos in `jaah-ai`: (1) the SDK repo (Python + TS packages, README quick-start). A new developer following the README alone gets a sample running on dev. ## Approach (architecture §3.5, §3.7, §3.8, DD1, DD9, DD17, DD20, DD21, RK2) 1. **Create BOTH private repos** jaah-ai/agent-sdk and jaah-ai/agent-connectors (genesis: README only), using the roster credential `users/roman@gmind.tech/github_admin` via the GitHub REST API (DD17; the App login gets 403 on org-admin endpoints). - First probe `jaah-forge api get /repos/jaah-ai/agent-sdk`. - If the App installation does not cover the new repos, drive clone/push/PR with the admin credential from a scratch dir OUTSIDE the worktree. Never write the token to disk, argv-visible logs or remotes. - Name the App-installation gap for the operator. - Keep both repos private (N4). 2. **Deploy key (DD20):** generate a read-only deploy key; install the public half on agent-sdk and the private half as Actions secret `AGENT_SDK_DEPLOY_KEY` on agent-connectors. No personal token stored. 3. **Python package `jaah_agent` + TS package `@jaah/agent-sdk`**, the same API (camelCase in TS), §3.8: ``` connect() -> Agent (raises NotARunner) Agent.task() -> TaskContext # agent.task; plus worktree (env JAAH_WORKTREE) and inputs (from file at env JAAH_AGENT_INPUTS) Agent.log(message, level="info", **data) # local events file Agent.report_usage(model, input_tokens, output_tokens, cache_read=0, cache_write=0) Agent.notify(message) # agent.notify Agent.ask(questions, poll_interval=5, timeout=None) -> list[Answer] # agent.ask then polls agent.answers until all_resolved; blocks Agent.credentials() / Agent.credential(name) # task.credential_list / task.credential_get Agent.artifact(kind, path) ; Agent.read_task(id) ; Agent.search_tasks(q) Agent.settle(summary, terminal_type, *, pr_url=None, no_pr_reason=None, no_pr_evidence=None, **gate) ; Agent.fail(reason) Errors: JaahUnavailable (retryable), JaahRefused(reason, detail) (never retried), NotARunner Answer = {status: "answered"|"dismissed", selections: list[str], text: str} ``` 4. **Wire:** one JSON line each way on the daemon socket at env `JAAH_AGENT_SOCKET`, with verbs exactly as §3.5: - existing: task.settle, task.fail, task.artifact, task.credential_list, task.credential_get, task.get, task.read, task.search; - new (served by K3): agent.task → {task:{id,title,body,persona,autonomous,out_of_scope}, project:{…}, agent:{…}, security_gate}; agent.ask {questions[1..4]:{question, header?, options[{label, description?}], multi_select, recommended_index?}} → {ids}; agent.answers {ids} → {rounds:[{id,status open|answered|dismissed,selections,text}], all_resolved}; agent.notify {message ≤2000} → {ok}. - Read the daemon's exact request/response framing from apps/jaahd/agent_socket.py in jaah. 5. **Events writer (§3.7):** to env `JAAH_AGENT_EVENTS`, O_APPEND, one write per line, every line with timestamp + type: - `log` {level, message, data}; - `usage` {message:{id uuid4, model, usage:{input_tokens, output_tokens, cache_read_input_tokens, cache_creation_input_tokens}}} — exactly the shape session_efficiency reads; - `sdk` {event, detail with NO values}. 6. **Masking (DD9):** keep an in-memory set of every value credential() returned; mask as `<redacted:name>` in every log/notify/ask/settle/fail text; credential_get events carry the name only. 7. **Package metadata:** the SDK VERSION file. Python is runnable with only stdlib (the node puts it on PYTHONPATH); TS is runnable on Node ≥22.18 with built-in type stripping (no build step needed at runtime: ship .js or erasable .ts). 8. **Tests and release:** - unit tests against a fake socket server for every call; - the parity test (import the Python package, enumerate public callables + error classes, assert a TS export of the camelCase name with the same arity); - CI (GitHub Actions) running both suites; - README quick-start (manifest example, Python + TS hello agent, the don't-daemonize rule, the no-SDK-in-deps rule); - tag `v0.1.0`. Credentials & reach (architecture §9, verbatim rows): - K6/K7 repo creation, deploy key, secrets, PRs in jaah-ai | `users/roman@gmind.tech/github_admin` (GitHub token); org `jaah-ai` | **verified**: the roster get succeeded. The launcher's App login got HTTP 403 on org-admin endpoints (P6), hence DD17. - K6/K7/K8 forge reads (tags, PR status, checks) | the launcher's GitHub App login via `jaah-forge` | **verified**. Out of scope: - Do NOT build the CP routes or daemon verbs (K3) or the node supervisor (K4). - Do NOT add connectors or CONTRIBUTING/GOVERNANCE content to agent-connectors (K7) — genesis README only. - Do NOT publish to PyPI/npm (N4). - Do NOT make either repo public (N4). - Epic fences (PRD §7, verbatim): - N1 Do not change the behaviour of the five built-in providers' launch, hook, transcript, quota, login or account-selection paths beyond what is needed to list them as built-ins (AC-1). Their adapter modules under apps/jaahd/agents/ are not to be rewritten in this epic (D3). - N2 Do not remove or weaken ADR-0155's human gate for non-Claude runners; SDK agents get no autonomous review lane (AS1). - N3 No plan/feature flag that defaults OFF for the org-agent and catalog features (D8). - N4 Do not make the SDK or connectors repos public (D17), and do not publish to public PyPI/npm. - N5 No token/crypto voting, no Discord dependency, no in-console bounty payments or Stripe integration for bounties. - N6 Do not route SDK agents through Jaah Accounts/quota/billing of model subscriptions (D20); do not add new provider rows to agent_providers.PROVIDERS for custom agents. - N7 No cross-org visibility of org-private agents (D12). - N8 Never write a credential value into a session log, artifact, report, or manifest. - N9 Do not widen the runner verb vocabulary for built-in runners' prompts or change the MCP tool names they use today. - Deferred: licence choice / going public. Done means: - Both repos exist in jaah-ai with visibility=private — observe via `jaah-forge api get /repos/jaah-ai/agent-sdk` and `/repos/jaah-ai/agent-connectors` (private:true). - The deploy key is present on agent-sdk (read-only) and secret AGENT_SDK_DEPLOY_KEY exists on agent-connectors — observe via the API listing (names only). - agent-sdk CI is green on the merged PR: Python + TS unit suites against the fake socket cover every §3.8 call. ask() returns a distinct `dismissed` Answer (not an empty answer) and blocks until all_resolved. JaahRefused is not retried. - The parity test passes and FAILS when a TS export is removed (demonstrate once, locally). - The masking test: a value returned by credential() is absent from the events file and from sent notify/settle/fail text. - The events usage line matches the §3.7 shape byte-for-byte keys. - Tag v0.1.0 exists. - README quick-start is complete enough that a developer could write a hello agent from it alone. - No token is written to any file, commit or log.

Outcome

Built jaah_agent (Py) + @jaah/agent-sdk (TS) v0.1.0 in jaah-ai/agent-sdk: PR https://github.com/jaah-ai/agent-sdk/pull/1 merged (578b4a8), CI green, tag v0.1.0. Both repos private; deploy key + AGENT_SDK_DEPLOY_KEY set. No jaah change. Gap: App can't admin new repos.

Artifacts

Activity

  • Draft
  • Ready
  • Runner started
  • Ready
  • Runner started
  • Runner ended (done)