{"id":"1b4453ec-8bc1-41f1-81e0-8959a80ef8a4","slug":"hanoon","kind":"skill","name":"hanoon","summary":"A private Telegram agent for BB: run your projects, threads and machines from chat, with durable memory, self-triggering monitors, and a reviewed delivery pipeline.","owner":"amrtawfik160","repoUrl":"https://github.com/amrtawfik160/hanoon","license":"MIT","licenseTier":"permissive","trust":"community","stars":6,"match":null,"fewStars":false,"format":"skill","createdAt":"2026-08-10T20:28:02.000Z","addedAt":"2026-10-21T17:53:01.502Z","logoUrl":"https://avatars.githubusercontent.com/u/60387027?u=3bbccc00f68518365b5fa8b886ade554c9cc1d4f&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["communication","data-analytics","memory-knowledge"],"tags":[],"runtime":"binary","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-26T03:02:17.981Z","sample":false,"url":"https://conduits.dev/tools/hanoon","language":"TypeScript","transports":["stdio"],"install":{},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# Hanoon\n\nHanoon is a private Telegram AI agent for BB. One paired owner runs their whole BB installation from a phone: ask questions, drive threads and machines, set monitors that follow up on their own, and ship code through a reviewed pipeline from planning to merge, deployment, and canary verification.\n\nThe installed plugin and CLI namespace remain `telegram-agent`.\n\n## Why Hanoon?\n\n- **Run BB from Telegram, not from BB.** Hanoon has the shell, the `bb` CLI, installed skills and MCP servers, and reach across every connected machine. A question or permission prompt it hits reaches you in Telegram; a block it cannot render into buttons is still reported, naming the thread and saying it needs you in BB.\n- **It remembers, and keeps it honest.** Standing preferences, decisions, and corrections persist in SQLite with full-text recall. Correcting Hanoon devalues whatever misled it, notes it never uses fade, and a correction retires the belief it contradicts.\n- **It learns from finished work.** When a job ends, Hanoon works out what is worth knowing about that repository next time — a check that always fails for a known reason, a convention it enforces — and keeps it per project.\n- **It follows up by itself.** Any thread Hanoon starts or messages is watched until it lands, including threads it did not open; you can also set a monitor on a schedule. When one fires, Hanoon does the work and messages you. It also runs its own daily and weekly upkeep, and stays quiet when nothing needs you.\n- **It works in parallel.** Independent questions go out to several BB threads at once and come back as one answer.\n- **Conversations survive failures.** A dead provider session retires a BB thread, not the conversation. The replacement resumes with what was said and what was already done.\n- **Pipeline workers recover safely.** Silent or missing workers are retired and the exact stage is retried only for failure signatures that have recovered before; unfamiliar failures still stop for you.\n- **Mutations happen once.** Every mutating tool call is receipted by turn and argument hash, so a recovered agent replays the result instead of repeating the action.\n- **Fail closed at the merge boundary.** Review and validation bind to the full pull-request head resolved from Git, and approval is one-use and expiring unless that project holds a standing grant — from the owner's button tap, or from its own policy. A project may only carry that grant if GitHub already requires a status check on its base branch, and repository rules still apply either way.\n- **Use BB's isolation model.** Threads isolate provider conversations and coordination; managed worktrees isolate branches, checkouts, and filesystem mutation.\n\n## How it works\n\nHanoon has three layers:\n\n| Layer | Responsibility |\n| --- | --- |\n| Telegram I/O | Poll the paired private chat, durably record input, and deliver drafts, status updates, confirmations, and final replies. |\n| Durable control | Store owner pairing, project policies, controller turns and conversation digest, memories, monitors, tool receipts, jobs, effects, approvals, liveness, and the outbox in plugin SQLite. |\n| BB execution | Run the hidden controller and visible planning, implementation, review, documentation, validation, merge, deployment, and canary work. |\n\nIngress never starts a BB session; it claims each Telegram update durably before anything acts on it. One generation-fenced executor owns controller dispatch, monitors, pipeline effects, and Telegram delivery. That executor may run bounded pipeline lanes for independent projects, while durable project claims keep each project serialized. Reviewers are newly spawned BB threads with fresh provider conversations; they reuse the implementation environment only to inspect the same worktree.\n\nAgent sessions run out of process as BB threads and never open the plugin database, so the single-writer SQLite store stays uncontended: state transitions, their effects, memory writes, and the conversation digest all commit in one transaction.\n\n## What Hanoon can do\n\n| Capability | What it means in the chat |\n| --- | --- |\n| Full BB control | \"Restart that host\", \"what's on machine two\" — the shell and `bb` CLI on any connected machine, under the configured permission mode. Installing or connecting an integration needs your decision first. |\n| Live thread insight | \"Why is this taking so long?\" answers from the thread's current step, todo list, running commands, and latest message — not just its status. |\n| Thread management | Open a thread to explore something, message a running one to answer its question or redirect it, stop or retry with a one-tap confirmation. |\n| Memory | \"Always deploy on weekday mornings\" is kept and applied later. Ask what it knows, or tell it to forget. Secrets are refused, never stored. |\n| Voice notes | Send a Telegram voice note or audio message. Hanoon durably queues transcription without storing the audio bytes, keeps later messages in order, and tells you plainly when transcription is unavailable or too long for one message. |\n| Reference documents | File project or global specifications, search their passages, and give every pipeline stage a bounded structural map of what governs the work. |\n| Working style | \"Be terser\" or \"always show me the PR link\" sticks, without a code change. It can shape tone and habits, never a safety boundary. |\n| Parallel work | \"Compare the invoice spike and the billing latency\" opens both at once and answers from what comes back. |\n| Self-maintenance | Daily stale-work and read-only repository audits, bounded cleanup of old allowlisted plugin temporary directories, a weekly memory audit, and a weekly scorecard. Off by one setting; disk-pressure warnings remain active. |\n| Monitors | \"Tell me when this finishes and open a PR\", or \"every weekday at 9, summarise the overnight runs.\" |\n| Thread notices | Every top-level thread reports itself: you are told when one finishes or fails, and a thread blocked on a question or a permission prompt asks you in Telegram with buttons. A block it cannot render is still reported, so nothing waits on you in silence. |\n| Answers you can check | Every reply is an accepted structured finalization backed by evidence gathered in that same turn. Raw model prose never becomes an answer, and a claim without compatible evidence is rejected rather than sent. |\n| Steering you can see | When the agent messages a worker thread it must say, in one line, what it asked for and why. You cannot see the threads, so that line is carried back on the reply that closes the turn: an instruction given in your name is visible while it still matters, not discoverable later. |\n| Reviewed delivery | A guarded job takes a change from plan to a reviewed pull request; merging and production ask you in Telegram unless you have given that project a standing grant. |\n| Unattended delivery | A project's policy can let it merge without asking, start work from its own daily audit, and revert an unattended merge that broke production. All three are off unless that policy asks for them, and each has preconditions before it is accepted. |\n| Self-diagnosis | `/health` reports the executor, queued work, undelivered messages, monitors, memory, and database integrity — even when the agent is the stuck part. |\n| Bounded turns | A question that runs away is nudged once to land the answer, then stopped before it burns your budget out of sight. |\n\n## What an answer is\n\nEvery owner-visible reply is one accepted structured finalization, plus what the agent asked worker threads to do on that turn. Nothing else can become one:\n\n- **Evidence in the same turn.** A claim about current state or completed work must reference evidence the agent gathered during that turn, with compatible proof kinds and a matching subject. Evidence is sealed at a high-water mark when the finalization is accepted, and an answer whose evidence advanced afterwards is refused rather than sent.\n- **Raw prose reaches nothing.** Unstructured assistant prose never becomes a Telegram draft, a stored answer, a conversation digest, an outbox row, a finalization row, or a reply. BB still owns its own provider transcript. Drafts show one of the fixed phase lines, such as \"Hanoon is thinking…\", never partial output. The one exception is not prose: when BB blocks on a question or an approval, the provider's own prompt, options, and command are what the owner is being asked about, so they are carried through — each field bounded and credential-screened, and the whole interaction downgraded to an unanswerable notice if any field fails the screen.\n- **What was asked in your name comes back.** Messaging a worker thread requires a one-line reason, recorded once the message has actually landed and owed to you until a reply states it. The reply is composed from that record rather than from anything the agent remembered to mention, so it cannot be skipped by wording. Because the record belongs to the agent rather than to one turn, an instruction sent by a turn that then dies is reported on the next reply instead of vanishing with it.\n- **A bounded capability surface.** The controller runs against an enforced manifest of exactly 35 Hanoon capabilities. Denials are decided before any effect, and a stale executor fence or a stale approval is denied rather than retried.\n- **Owner boundaries reach the phone.** A hidden-controller question or BB permission prompt is fetched from BB by exact identity, shown in Telegram, and answered by tap or plain reply. Approvals offer exactly *Allow once* and *Deny*; there is no session-wide grant on the hidden controller path. Your tap commits durably before BB is told, survives a restart, and is retried only for that exact resolution.\n- **One logical reply, recoverable at-least-once transport.** The answer is one durable outbox obligation. Server-directed backoffs, transient failures known not to have sent, and uncertain brand-new sends remain on the same logical outbox row for bounded scheduler retries; an uncertain retry may duplicate the Telegram message, while edits retry against their stored message id. If uncertainty exhausts the retry budget, that same row becomes a vetted delivery-warning obligation with a fresh retry budget instead of disappearing silently. Enqueuing or attempting is never recorded as delivered.\n\n## Credential broker foundation (disabled by default)\n\nHanoon carries the first slice of a separate credential broker: a protected service, run outside this plugin, that exposes a health-check contract, a single vault-item resolution contract, and fixed provider-identity probes for enrolled Convex or Vercel targets. The Vercel browser operation is governed by the same typed contract but remains unavailable in the default server composition until an isolated browser administrator is supplied. **Credential broker mode defaults to `disabled`**; enabling it requires a protected broker host and the deployment's own reviewed provider acceptance evidence.\n\nWhile it applies, this foundation only ever proves that the broker can reach a configured vault item — never that the resulting credential works for its application:\n\n- `bb telegram-agent access list` and `bb telegram-agent access status [binding-id]` are read-only local, secret-free inspections. `bb telegram-agent access reconcile <project-id> --projection-json <json> --json` is a mutating local Hanoon projection import: it accepts only a validated, secret-free projection from protected-host enrollment while an active controller project/thread and executor lease are present; it never contacts the broker or resolves or verifies a credential.\n- The owner can ask Hanoon in Telegram to run a live verification of one known binding; a pass moves that binding to `vault_verified`, never `active`, and Hanoon never claims an application login succeeded from it.\n- A protected-host operator enrolls a typed connector target with `connector binding enroll --stdin`. The broker atomically stores the encrypted target/reference and policy, then returns a secret-free projection for Hanoon reconciliation. No credential or live provider resource is created by enrollment.\n- Connector inspection uses the exact selected capability and fixed adapter route. Current broker readiness, topology, audit, fence, receipt, and target identity are checked before and after dispatch; ambiguous retries reuse the persisted envelope.\n- The checked-in recovery proof uses only local synthetic vault and TLS-provider fixtures. It proves controller-fenced projection reconciliation, bounded cancellation for an injected abortable adapter port, receipts, restart/ambiguity replay, and canary absence without claiming that a live provider or credential was contacted.\n- The installed `@1password/sdk` 0.5.0 exposes neither an abort signal for `Secrets.resolveAll` nor a public client close/dispose operation. Production SDK-backed credential resolution therefore fails closed before starting that unbounded SDK operation; the SDK-backed provider identity route remains unavailable until a genuinely cancellable/closable transport is supplied.\n- `bb telegram-agent doctor` reports one `credential broker` row, `disabled`, until isolated mode is configured, and one row per readiness check afterwards; see [Configuration](docs/configuration.md#credential-broker-foundation) and [Operations](docs/operations.md#credential-broker).\n\n## Architecture\n\n<p align=\"center\">\n  <img src=\"docs/assets/architecture.svg\" alt=\"Hanoon architecture: private Telegram chat → I/O bridge → durable SQLite control plane → single leased executor → isolated BB controller and pipeline threads backed by a managed Git worktree\" width=\"680\">\n</p>\n\nRead the [architecture guide](docs/architecture.md) for diagrams, state ownership, and the exact BB thread/worktree boundary.\n\n## Pipeline\n\n<p align=\"center\">\n  <img src=\"docs/assets/reviewed-pipeline.svg\" alt=\"Reviewed delivery pipeline: intake → plan → critique → build → test → fresh review → docs → final test and review → owner approval → merge → deploy → canary → complete, with bounded critique and patch loops\" width=\"960\">\n</p>\n\nCritique can request one replacement plan. Test or review failures return to a bounded patch/test/review cycle. Full jobs require independent quality and risk reviews; small fixes still run deterministic validation plus one quality review. Existing open pull requests can be adopted with planning and critique recorded as skipped. Invalid evidence, stale pull-request heads, exhausted limits, novel worker failures, and expired approvals block instead of silently advancing.\n\nThe approval stage has two ways past it. By default it waits for your tap. A project holding a standing grant passes it without asking, on exactly the same evidence, and a change that argued with its own review twice still needs a second independent review before that grant covers it. A project with no production settings finishes at the reviewed pull request unless its policy opted into merging without one, which ends the job at `merged` with nothing to deploy. See [Configuration](docs/configuration.md#unattended-delivery) for what a project must have before it may do any of that.\n\nThe project policy chooses implementation/review providers and commands. The conversational agent is configured independently and defaults to Claude Opus 5 (1M) at `xhigh` reasoning. Claude Code, Codex, Cursor, and Grok models are selectable; the catalog picks the provider for each model id. The concurrent-job cap defaults to `5`, accepts `1`–`8`, and applies to later admissions without cancelling work already admitted.\n\n### Adaptive capability routing\n\nNew jobs are admitted as navigator-v1 in deterministic mode. The classifier, recipe policy, stage projection, and recipe-keyed skill or model selection do not control or admit new work. A leftover `task_recipe` column may remain on the job row, but it does not route new work.\n\nHistorical recipe promotion still exists as leftover recipe-v1 history. Adaptive recipes defaulted to `shadow`, where candidate routing was observational and could not control production behavior or manufacture success receipts. A recipe became active for leftover jobs only after an append-only promotion decision backed by a resolved durable evidence ledger. The production reader verifies recorded artifacts, an active post-merge job, failure/recovery chronology, and model trials against authoritative SQLite rows. This release exposes no operator or typed-envelope ingestion path and includes no trusted live collector, so a fresh installation cannot produce promotion evidence and no leftover recipe is enabled merely because deterministic tests pass. See [Operations](docs/operations.md#capability-routing-and-rollout) for inspection and rollback commands.\n\n## Bundled agent skills\n\nThe plugin carries a deterministic 35-skill catalog. It vendors the 25 skills in the reviewed Matt Pocock plugin manifest at revision `6654f6b60cd9d5be8b54c6fafe44346dabeb3b76`, plus ten Hanoon, guard, writing, visualization, and communication skills. Superpowers workflow ids, the duplicate discovery root, and the proportional workflow router are not installed. Every source tree, invocation class, provenance record, license, and supporting file is locked locally. Plugin startup performs no skill download or repair, and it refuses to start while a nonterminal recipe-v1 job still needs a legacy skill or state handler.\n\nBB discovers skills one directory below each registered root, so the manifest registers the Matt Pocock `engineering` and `productivity` buckets separately. New work uses the workflow navigator. Historical recipe columns, descriptors, and receipts remain readable.\n\n| Verified context | Selected skill ids |\n| --- | --- |\n| controller | `driving-bb`, `unslop`, and on an explicit grill request `grill-with-docs`, `grilling`, `domain-modeling`. Conduct requires unslop on every owner-facing message. |\n| planner | `unslop`, `writing-for-agents`, `docs-guard` |\n| critic | `unslop` |\n| implementation | `unslop`, `diagnosing-bugs`, `tdd`, `clean-code-guard`, `test-guard`, `durable-boundary-audit`, `show-me` |\n| review | `unslop`, `clean-code-guard`, `test-guard`, `durable-boundary-audit`, `blast-radius`, `code-review` |\n| documentation | `unslop`, `technical-writing`, `docs-guard` |\n| final-review | `unslop`, `clean-code-guard`, `test-guard`, `docs-guard`, `durable-boundary-audit`, `blast-radius` |\n| validation, merge, deploy, canary | none; these stages remain deterministic |\n\nThe admission catalog records whether each skill is model-invoked or must be explicitly scheduled by the owner or workflow navigator. General worker selection rejects user-invoked skills. A skill never grants tools, credentials, merge authority, or production authority.\n\nSelection is fail-closed. Structurally, a worker must be from plugin `telegram-agent` with a non-fork origin, use a `standard` project and a `managed-worktree`, and have an anchored title of the form `Telegram <jobId> <role-token> <attemptId>`. Job ids are 1 to 256 characters from `[A-Za-z0-9_-]`; attempt ids are 1 to 264 characters from `[A-Za-z0-9_.:-]`. Durably, the exact attempt or stage record, effect, project, environment, thread, role, and routing mode must match. Any mismatch receives no tools and no skills.\n\n`npm run skills:verify` validates the registered roots, the schema 2 lock, the 35-skill catalog with empty legacy and shadow lists, bounded regular files, frontmatter, nested local Markdown resources, provenance, licenses, and every SHA-256 file digest. Success prints a bounded `bundleDigest`, `admittedSkillCount`, and `legacySkillCount`. Build and activation run the same verifier before plugin code can register. A missing, unlocked, escaped, oversized, symlinked, malformed, leftover-kit, or digest-mismatched bundle fails closed.\n\nA maintainer can refresh the promoted portfolio only from an already-reviewed clean local checkout at the pinned full revision:\n\n```bash\nMATT_SKILLS_SOURCE=/absolute/path/to/mattpocock-skills\nMATT_SKILLS_REVISION=6654f6b60cd9d5be8b54c6fafe44346dabeb3b76\nnpm run skills:sync -- --source \"$MATT_SKILLS_SOURCE\" --revision \"$MATT_SKILLS_REVISION\"\n```\n\nThe synchronizer verifies the checkout identity, manifest, package metadata, license, promoted paths, invocation metadata, and bounded source tree before atomically replacing `skills/matt-pocock` and the lock. It has no runtime role.\n\n> [!WARNING]\n> This is a full-trust BB plugin. Fresh or unset controller permission settings resolve to `auto`; an explicitly saved `auto`, `accept-edits`, or `full` value is preserved. BB-native permission prompts raised for the hidden controller can be bridged into Telegram as *Allow once* / *Deny*. An enabled project policy may run owner-authored validation, deployment, and canary commands.\n>\n> Merging a pull request and promoting to production require a Telegram approval from the owner, one-use and expiring — **unless that project holds a standing grant**. A grant comes either from the owner's own button tap or from `autonomy.unattendedMerge` in the project's policy, and both replace the owner's signature and nothing else: every review, validation, and evidence gate still runs. `bb telegram-agent project enable` refuses to store either grant unless GitHub already requires a status check on that base branch, and warns when the protection does not bind administrators. `/approvals off` withdraws a grant, and a failed production rollback withdraws it automatically and stops the project taking new work.\n>\n> Review the source and policy, keep GitHub protection enabled, and use a disposable repository for the first live run.\n\n## Quick start\n\n### 1. Install from a checkout\n\nRequirements: BB `0.36` or newer, npm, an authenticated GitHub CLI on each project source host, a standard BB GitHub project, access to at least one of Claude Code, Codex, Cursor, or Grok, and a Telegram bot from [BotFather](https://core.telegram.org/bots#botfather).\n\n```bash\nnpm ci\nnpm run check\nbb plugin install . --yes\nbb plugin enable telegram-agent\nbb plugin reload telegram-agent\n```\n\n### 2. Configure and pair\n\nIn **Extensions → Plugins → Telegram Agent**, enter the Telegram bot token in the secret setting. The model, reasoning level, service tier, permission mode, and maximum concurrent jobs are on the same page; the defaults are ready to use.\n\n```bash\nbb telegram-agent pair\nbb telegram-agent doctor\n```\n\nOpen the sensitive, ten-minute pairing link from the intended owner's private Telegram chat.\n\n### 3. Enable a project\n\nCreate a reviewed project policy, then enable and validate it:\n\n```bash\nbb telegram-agent project enable proj_7f3d2a91 --policy-file /absolute/path/to/policy.json\nbb telegram-agent doctor proj_7f3d2a91\n```\n\nThe policy defines the exact GitHub repository/base branch, worker profiles, validation commands, required checks, redaction patterns, review limit, merge method, and optional deployment/canary commands. Projects that deploy to the same target can share `production.targetKey`, which serializes that target even when their repositories differ. See [Configuration](docs/configuration.md) for the complete verified schema and examples.\n\nSelf-healing is off by default. To enable it, set the boolean `selfDiagnosisEnabled` to `true`, set `selfDiagnosisProjectId` to the enabled project containing this checkout, and reload the plugin. It inspects persisted controller and pipeline job failures out of band, requires the fixing worker to report what verification ran before any fix is proposed, and proposes at most one cooled-down fix at a time, messaging the owner the link without asking. `selfDiagnosisMode` decides what that fix becomes: `draft-pr` (the default) pushes a branch for you to read, and `pipeline` files it as an ordinary reviewed job instead, under the same `autonomy.intake` allowance and finding ledger as the daily audit. Neither mode merges anything or changes an existing pull request.\n\n### 4. Talk to Hanoon\n\nSend a normal private message. Hanoon answers conversationally, and acts when asked. Screenshots, GIFs, and short videos are part of the same turn — clips are sampled into stills the agent can see. PDF, Markdown, and plain-text files are attached to the turn too, with their caption kept as the message, and short text files are read inline. Several messages sent in quick succession are answered together as one burst, and a forwarded message keeps the name of who wrote it.\n\n```text\nwhat's running right now?\nwhy is the billing thread taking so long?\nopen a thread on cyndra to look into the invoice spike\ntell me when it's done and summarise what changed\nalways deploy parknwash on weekday mornings\n/health\n```\n\nRecovery commands remain available without the agent: `/status`, `/projects`, `/health`, `/approvals`, `/resume`, `/retry [job-id]`, `/cancel [job-id]`. `/status` lists current jobs; replying to a job status message or supplying its id selects that exact job. `/approvals` lists the projects that merge without asking and says whether each was granted by button or set in its policy; `/approvals off [alias]` withdraws one, or all of them with no alias. `/resume` lists the projects the failure brake stopped and `/resume <name>` starts one, or `/resume all` starts every one. Merging still requires a Telegram approval unless that project holds a standing grant.\n\n## Documentation\n\n| Guide | Use it for |\n| --- | --- |\n| [Documentation index](docs/README.md) | Find operator, contributor, security, and design-history material. |\n| [Architecture](docs/architecture.md) | Understand ownership, durability, review isolation, and worktree boundaries. |\n| [Configuration](docs/configuration.md) | Install, pair, select a controller profile, and enable project policies. |\n| [Operations](docs/operations.md) | Inspect, retry, cancel, rotate credentials, recover, and remove. |\n| [Disposable live acceptance](docs/live-acceptance.md) | Prove the end-to-end pipeline without risking a production repository. |\n| [Contributing](CONTRIBUTING.md) | Set up development and prepare a reviewable change. |\n| [Security](SECURITY.md) | Report vulnerabilities and understand the trust model. |\n\n## Repository layout\n\n```text\nhanoon/\n├── src/\n│   ├── bb/           # BB thread, environment, handoff, validation, and merge adapters\n│   ├── controller/   # Durable conversational controller and guarded native tools\n│   ├── domain/       # Project policies, job state machine, review, and pipeline graph\n│   ├── services/     # Leased executor, effects, review, merge, production, and liveness\n│   ├── storage/      # SQLite migrations and transactional store\n│   └── telegram/     # Telegram API client, ingress, errors, and bounded rendering\n├── tests/            # Unit, integration, state-machine, and mocked end-to-end coverage\n├── skills/           # Pinned admitted catalog plus temporary recipe compatibility skills\n├── evals/            # Golden answers for the opt-in response-quality check\n├── docs/             # Public guides plus design/implementation history\n├── server.ts         # BB plugin entry point\n└── package.json      # Plugin manifest and verification scripts\n```\n\n## Development\n\n```bash\nnpm ci\nnpm run typecheck\nnpm run skills:verify\nnpm run build\nbb plugin types --check .\n```\n\nType checking resolves `@get-bb/plugin-sdk` from the exact version pinned in `devDependencies`. Run `bb plugin types --check` to confirm that this pin matches the installed BB; `bb plugin types` updates it when BB changes.\n\n> [!NOTE]\n> The test suite also imports `@get-bb/plugin-sdk/testing` from that pinned package. `npm run check` runs typecheck, tests, the plugin build, artifact verification, and the credential-broker TypeScript build from a clean install.\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for change boundaries, documentation checks, and pull-request evidence.\n\n## Project status\n\nVersion `0.1.0`, installed directly from a checkout. There is no package registry or release channel. The repository is licensed under the [MIT License](LICENSE).\n"}