Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,12 @@ node skills/run-braintied-research/scripts/run-internal-research.mjs \

The internal runner uses Braintied Agent Auth from `BRAINTIED_AGENT_TOKEN` or
macOS Keychain and keeps all model/search provider credentials in Cortex Worker.
Live execution requires the authenticated catalog's durable protocol v2: the
client submits one idempotent request, records the server-owned run ID, and
polls the tenant-bound result. A dropped response or rolling deployment is
retried with the same request ID instead of starting a second paid run. Preserve
the printed request ID; `--request-id <id>` explicitly reattaches after a local
timeout or interruption.
`run-research.mjs` remains available as an explicit local-provider fallback; it
supports allowlisted interactive-shell environment loading and build-freshness
checks. Exact lane preflight requires an as-of date:
Expand Down Expand Up @@ -198,7 +204,7 @@ npm run pack:release # → releases/braintied-research-<version>.tgz

```jsonc
// consumer package.json
"@braintied/research": "file:vendor/braintied-research-0.6.4.tgz"
"@braintied/research": "file:vendor/braintied-research-0.8.1.tgz"
```

## Development
Expand Down
67 changes: 67 additions & 0 deletions docs/internal-agent-research-release-2026-07-23.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Internal Agent Research Release — July 23, 2026

## Outcome

`@braintied/research` 0.8.1 replaces the long-lived HTTP execution contract
with resumable, idempotent durable polling. It is the client-side half of Cortex
internal-tools protocol v2 and is required for paid agent research.

## Root cause

Version 0.8.0 kept a deep research request attached to one Fly Machine. JSON
whitespace heartbeats prevented idle proxy timeouts, but a rolling Machine
replacement still severed the live request after provider work had begun. The
client could not determine whether work or billing continued and a retry risked
starting a second attempt.

## Durable contract

- The authenticated catalog must advertise protocol v2 and exact same-origin
submission/status paths.
- Submission uses one caller request ID as its idempotency key. The client may
retry a dropped submission without creating another durable record.
- The server returns a run UUID; the client polls its authenticated status and
validates the final result before writing any artifact.
- `--request-id` reattaches a later CLI process to the same attempt.
- Temporary transport, `404`, `408`, `425`, `429`, `502`, `503`, and `504`
responses use bounded retry delays within the caller's deadline.
- Metadata and stdout expose the request ID and durable run ID, never the Agent
Auth token, provider credentials, raw trusted recall, or provider error body.
- A protocol-v1/stream-only deployment is rejected before a paid call.

## Deployment exclusion

The matching Cortex release persists tenant-bound runs before Inngest dispatch.
Its deployment script acquires an atomic database lease only when no unexpired
run is queued/running. The same locked row pauses new submissions until the
rolling deploy completes, closing the check-then-deploy race. Lease expiry is
bounded so a dead deploy process cannot create an indefinite outage.

## Operator recovery

When a client deadline or local process interruption occurs, do not infer zero
cost and do not issue a new request ID. Repeat the identical command with the
reported `--request-id`; the client will retrieve or continue polling the
existing durable record. A fresh ID is a deliberately separate paid run.

## Acceptance gates

Package acceptance passed:

- unit and contract tests: 56/56;
- Instagram/Bright Data boundary tests: 8/8;
- TypeScript and production build;
- CommonJS, ESM, packaged CLI, and exact version import from a clean tarball
consumer;
- clean production dependency audit: zero vulnerabilities;
- exact 14-file tarball audit plus Gitleaks and high-confidence provider,
Agent Auth, Swishh, GitHub, Slack, and private-key signatures: no leaks;
- archive: `releases/braintied-research-0.8.1.tgz`;
- SHA-256:
`901a1734195d060e47fe5f34bb9b5fb540f7afa3a81e374fed9aebff7e0c05ea`;
- npm integrity:
`sha512-w/GrdkCn56vmlQ+gExVPE4F/NHDbttS2xAkgE33N7fKBJcbwZ8eBEacYKXJbfwF0FQaTxBVNUmFuoTw2gd9zPw==`.

Production acceptance additionally requires a protocol-v2 catalog probe plus a
transport-loss canary that destroys the first submission socket after
persistence and proves the retry returns the same run.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@braintied/research",
"version": "0.8.0",
"version": "0.8.1",
"description": "Deep-research engine — multi-provider search, quote extraction, synthesis, critique, grounded report assembly, and research-driven document generation (PRDs, briefs, specs)",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
Expand Down
16 changes: 15 additions & 1 deletion skills/run-braintied-research/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ model providers; treat every brief as outbound data.
```

A token-presence check alone is not deployment health. Do not continue on a
missing route, failed authentication, or catalog without `research.run`.
missing route, failed authentication, or a catalog that lacks durable
protocol v2 submission/status endpoints for `research.run`.

5. **Run only after the outbound brief, credentials, and remote catalog are authorized.** Pass
`--allow-external`, an explicit report path, and a metadata path:
Expand All @@ -72,6 +73,14 @@ model providers; treat every brief as outbound data.
--allow-external
```

The server persists the authenticated input before dispatch and returns a
durable run ID. Submission and status requests retry bounded transport and
temporary-service failures with the same request ID. If the local deadline
or process interrupts the client, rerun the identical command with the
printed `--request-id <id>` to reattach; never choose a fresh ID for the same
paid attempt. Cortex deploys atomically exclude queued/running research, so a
normal rolling release cannot cut a paid run in half.

Use `run-research.mjs` only as an explicitly authorized local fallback when
the internal service is unavailable. That fallback requires package build
freshness plus its own provider credentials; `--load-shell-env` imports only
Expand Down Expand Up @@ -187,6 +196,11 @@ report **incurred cost `$0.00`** and say that engine `cost_usd` metadata and
grounding were **not produced**; do not describe either as `null`. If standalone
provider probes were made, report their known quota/credit cost separately.

For an interrupted internal run, distinguish client transport from server
execution. Preserve its request ID and use `--request-id` to retrieve the same
durable record. Do not report `$0.00`, infer provider cost, or start a replacement
run until the durable status proves the original attempt terminal.

Run `node skills/run-braintied-research/scripts/run-internal-research.mjs --help`
for the default internal surface and `run-research.mjs --help` for the local
fallback. Read [references/runtime.md](references/runtime.md) when
Expand Down
29 changes: 22 additions & 7 deletions skills/run-braintied-research/references/runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,28 @@ tool request requires an agent identity, `cortex` product access, and an
execution-capable scope (`execute`, `write`, `admin`, `master`, or `*`). The
initial registry exposes `research.run`; provider keys are never returned.

Deep requests default to a 3,600-second client deadline; other kinds default to
1,200 seconds. The Cortex route commits response headers immediately for long
work and emits JSON-whitespace heartbeats every 15 seconds before one final JSON
envelope. Do not place a buffering proxy in this path. A transport failure
reports only its sanitized error name/cause code and request ID. A streamed
HTTP 200 is not itself success: the client requires `ok: true` and a non-empty
report before it writes any artifact.
Live runs require internal-tools protocol v2. The client POSTs the request once
to the catalog-advertised durable submission path, then polls the advertised
tenant-bound status path until it receives a terminal result. Cortex persists
the validated input before Inngest dispatch, binds idempotency to the complete
organization/user/agent/request identity, and retains results for 24 hours.
Submission retries, temporary `404`/`429`/`5xx` responses, and transport loss
reuse the same request ID. A response lost after persistence therefore
reattaches instead of paying for a second run.

Deep requests default to a 3,600-second local client deadline; other kinds
default to 1,200 seconds. The deadline stops polling, not the server-owned run.
Preserve the request ID from the diagnostic and repeat the same invocation with
`--request-id <id>` to resume. Metadata records both `request_id` and
`durable_run_id`. A successful HTTP response is not itself success: the client
requires the strict completed result envelope and a non-empty report before it
writes artifacts.

Cortex deployments acquire an atomic database exclusion lease. Lease
acquisition fails while any unexpired research run is queued/running, and new
submissions receive retryable `503` responses while the lease is held. The
lease has a bounded expiry so a killed deploy client cannot pause research
indefinitely.

## Local provider fallback: package and build

Expand Down
Loading