Skip to content

docs(design): starter-credits bridge and write-only secrets - #6183

Open
mmabrouk wants to merge 1 commit into
release/v0.114.0from
docs/starter-credits-bridge-design
Open

docs(design): starter-credits bridge and write-only secrets#6183
mmabrouk wants to merge 1 commit into
release/v0.114.0from
docs/starter-credits-bridge-design

Conversation

@mmabrouk

Copy link
Copy Markdown
Member

Context

The starter-credits bridge lands across six PRs (#6138, #6164, #6165, #6168, #6174,
#6179), and the reasoning behind it lives nowhere a reader of this repository can find it.
The code carries the invariants in comments, but not the options each decision was chosen
against.

This PR is docs only. It adds docs/design/starter-credits-bridge/, written against the
code on those branches rather than against an earlier draft, because several decisions
moved during implementation (the repair path was removed, the mint policy became
payload-only, the proxy grew a second address).

Changes

Four files:

  • README.md. What the bridge does, the path from signup to exhaustion, a table of every
    piece and where it lives, and the eight AGENTA_STARTER_CREDITS_BRIDGE_* variables with
    which ones are needed to arm it.
  • design.md. Each decision with its options and the reason: one key per organization
    rather than a shared key, a vault connection rather than a new funded route, write-only
    and managed on the seeded row, the mint policy as an operator-controlled payload that
    fails closed, per-key rate limits, no repair path, new signups only, and why the
    connection's display name is part of the contract. Also the failure-mode table and the
    teardown order.
  • write-only-secrets.md. The vault contract the seeded row depends on: the one-way
    write_only flag, has_key and key_preview, keep-stored-on-omit, the secret-resolve
    grant that keeps the runtime reading plaintext, and managed_by with its 409. It cites
    the files and points at the two companion design folders for the full mechanism.
  • proxy-and-deployment.md. What a proxy has to provide, why the bridge holds a public and
    a private address for it, the two routing shapes and the one property that separates them,
    the HTTPS-only constraint on a seeded connection URL, and what a sandbox can and cannot
    reach.

Notes

@mmabrouk

Copy link
Copy Markdown
Member Author

@coderabbitai review

@vercel

vercel Bot commented Aug 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview Aug 21, 2026 7:49pm

Request Review

@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. documentation Improvements or additions to documentation labels Aug 21, 2026
@coderabbitai

coderabbitai Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor
❌ Action failed

Review failed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Oops, something went wrong! Please try again later. 🐰 💔

@coderabbitai

coderabbitai Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Documentation
    • Added comprehensive guidance for the starter-credits bridge, including signup provisioning, eligibility, credit usage, limits, exhaustion handling, and teardown.
    • Documented deployment requirements, proxy routing, HTTPS configuration, sandbox secrets, and spending controls.
    • Defined vault secret protections, redaction, updates, runtime access, and managed ownership rules.
    • Linked implementation components, configuration requirements, policy handling, and related design considerations.

Walkthrough

Added four design documents for the starter-credits bridge. The documents define signup provisioning, policy and budget controls, vault contracts, proxy deployment, failure handling, and teardown sequencing.

Changes

Starter-credits bridge

Layer / File(s) Summary
Bridge lifecycle and eligibility
docs/design/starter-credits-bridge/README.md, docs/design/starter-credits-bridge/design.md
Documents virtual keys, signup-only provisioning, mint policies, eligibility limits, team budgets, and the end-to-end flow.
Vault secret and ownership contract
docs/design/starter-credits-bridge/design.md, docs/design/starter-credits-bridge/write-only-secrets.md
Defines write-only secrets, managed vault rows, credential carry-over, mutation restrictions, naming rules, and orphan-key handling.
Proxy enforcement and deployment
docs/design/starter-credits-bridge/proxy-and-deployment.md
Documents proxy limits, shared spend state, public and private URLs, routing options, HTTPS requirements, and sandbox secret substitution.
Runtime failures and teardown
docs/design/starter-credits-bridge/design.md
Defines proxy error classification, failure behavior, and ordered teardown operations.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: 🟡 Moderate · up to 3bfd3

The documentation currently omits several concrete behavior and deployment constraints, including when new organizations qualify, which proxy URLs are valid, how policy changes affect active keys, how teardown and failed writes behave, how proxy errors are classified, and how development defaults are prevented from arming production. These omissions could lead to incorrect setup or unsafe runtime behavior, so follow-up is needed before merge.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0 files. (4 skipped: 4 unsupported.)
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the starter-credits bridge and write-only secrets documentation added by the pull request.
Description check ✅ Passed The description directly explains the documentation changes, covered designs, implementation context, and scope.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/starter-credits-bridge-design

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor
❌ Action failed

Review failed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Oops, something went wrong! Please try again later. 🐰 💔

@coderabbitai

coderabbitai Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor
❌ Action failed

Review failed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Oops, something went wrong! Please try again later. 🐰 💔

@coderabbitai

coderabbitai Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 330c2687-cc20-46f6-8b6f-d2673cef65c4

📥 Commits

Reviewing files that changed from the base of the PR and between 53717db and 3bfd3df.

📒 Files selected for processing (4)
  • docs/design/starter-credits-bridge/README.md
  • docs/design/starter-credits-bridge/design.md
  • docs/design/starter-credits-bridge/proxy-and-deployment.md
  • docs/design/starter-credits-bridge/write-only-secrets.md

Included review availability: Your plan provides up to 8 included reviews per hour; 2 remain after this review.

Comment on lines +138 to +146
Resolution is deliberately awkward, and every branch fails toward not seeding:

| Situation | Result |
| --- | --- |
| Live payload present and valid | Seed. The payload is cached for transport outages |
| Live payload present and malformed | Do not seed. Alert the operator. The cache is deliberately not consulted, because a bad rollout must never silently keep the old caps |
| PostHog reachable, no payload | Do not seed. A reachable source with nothing to say is a real "no policy" signal |
| PostHog unreachable | Use the cached payload if there is one, otherwise do not seed |
| The deployment configured no PostHog key of its own | Use the built-in development policy |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- candidate files ---'
git ls-files | rg '(^|/)(design\.md|.*starter.*credits.*|.*credits.*bridge.*)$|posthog|teardown|cache' | head -200
printf '%s\n' '--- design references ---'
rg -n -i -C 4 'cache|teardown|clear(ing)?|disable|seed|PostHog|payload|resolver|outage' docs/design/starter-credits-bridge/design.md
printf '%s\n' '--- related repository references ---'
rg -n -i -C 3 'starter.?credits|credits.?bridge|cached payload|cache invalid|clear.*payload|PostHog unreachable|no policy' . --glob '!node_modules' --glob '!dist' --glob '!build' | head -400

Repository: Agenta-AI/agenta

Length of output: 50373


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- design size and focused sections ---'
wc -l docs/design/starter-credits-bridge/design.md
sed -n '100,180p' docs/design/starter-credits-bridge/design.md
sed -n '180,280p' docs/design/starter-credits-bridge/design.md
printf '%s\n' '--- tracked files with focused names ---'
git ls-files | rg -i 'starter|credit|posthog|bridge' | head -200
printf '%s\n' '--- focused references outside generated/schema files ---'
git grep -n -i -E 'starter.?credits|credits.?bridge|cached payload|cache invalid|clear.*payload|PostHog unreachable|no policy' -- ':!**/openapi*' ':!**/schema*' ':!**/generated/**' ':!**/node_modules/**' | head -300

Repository: Agenta-AI/agenta

Length of output: 25936


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- design tail ---'
cat -n docs/design/starter-credits-bridge/design.md | sed -n '280,339p'
printf '%s\n' '--- README focused sections ---'
cat -n docs/design/starter-credits-bridge/README.md | sed -n '1,110p'
printf '%s\n' '--- proxy and deployment focused sections ---'
wc -l docs/design/starter-credits-bridge/proxy-and-deployment.md
rg -n -i -C 8 'teardown|stop|clear|payload|cache|disable|PostHog|seed' docs/design/starter-credits-bridge/proxy-and-deployment.md

Repository: Agenta-AI/agenta

Length of output: 16014


🏁 Script executed:

#!/bin/bash
set -e
python3 - <<'PY'
from pathlib import Path

p = Path("docs/design/starter-credits-bridge/design.md")
lines = p.read_text().splitlines()

resolution = "\n".join(lines[132:146])
teardown = "\n".join(lines[314:321])

checks = {
    "valid live payload is cached": "payload is cached" in resolution,
    "PostHog outage uses cache": "PostHog unreachable" in resolution and "cached payload" in resolution,
    "clearing live payload is teardown step": "clearing the policy payload" in teardown,
    "teardown explicitly invalidates cache": any(
        term in teardown.lower()
        for term in ("invalidate", "cache", "disable check", "clear the cache")
    ),
}
for name, result in checks.items():
    print(f"{name}: {result}")

print("\n--- resolver branch ---")
print("live payload cleared + PostHog unreachable => cached payload selected")
print("--- teardown text ---")
print(teardown)
PY

Repository: Agenta-AI/agenta

Length of output: 695


Make teardown independent of the cached policy. If teardown clears the live payload while PostHog is unreachable, the resolver still uses the cached payload and seeds new signups. Add a local disable check before cache use or explicitly invalidate the cache.

🧰 Tools
🪛 LanguageTool

[grammar] ~138-~138: Ensure spelling is correct
Context: ...ward, and every branch fails toward not seeding: | Situation | Result | | --- | --- | | L...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

Comment on lines +160 to +175
## Per-key concurrency and throughput caps

Every minted key carries a maximum number of parallel requests, a requests-per-minute
limit, and a tokens-per-minute limit, all from the policy payload.

The grant alone bounds what one organization can spend in total. It does not bound how
fast. Two things break under speed rather than volume. The upstream provider's throughput
quota is shared by everything the operator's credential serves, so one organization
looping calls can starve every other funded organization. And a burst that drains a grant
in minutes turns a trial into an error message before the person has typed a second
message.

The proxy also enforces its own upper bounds on what a key may be issued with. Raising a
policy value above the proxy's ceiling makes every mint fail with HTTP 400 until the proxy
configuration is raised and redeployed. Lowering a value is a live payload edit. That
asymmetry is intentional: loosening requires two people and a deploy, tightening does not.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- candidate files ---'
git ls-files | rg '(^|/)(design\.md|.*(bridge|policy|virtual.*key|key).*)$' | head -200
printf '%s\n' '--- relevant symbols and phrases ---'
rg -n -S -i 'starter.?credits|virtual key|per-key|policy payload|PostHog|mint|grant|tokens-per-minute|requests-per-minute|parallel requests|active bridge|block|update' docs src .github 2>/dev/null | head -300

Repository: Agenta-AI/agenta

Length of output: 47781


🏁 Script executed:

#!/bin/bash
set -eu
for f in docs/design/starter-credits-bridge/README.md \
         docs/design/starter-credits-bridge/design.md \
         docs/design/starter-credits-bridge/proxy-and-deployment.md \
         docs/design/starter-credits-bridge/write-only-secrets.md; do
  echo "--- $f ($(wc -l < "$f") lines) ---"
  cat -n "$f"
done

Repository: Agenta-AI/agenta

Length of output: 45177


🏁 Script executed:

#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re

root = Path("docs/design/starter-credits-bridge")
terms = re.compile(
    r"\b(existing|active|future|mint|minted|issued|policy|payload|"
    r"update|change|lower|tighten|block|block all|revoke|unblock|"
    r"bulk|every virtual key|never touches)\b",
    re.I,
)
for path in sorted(root.glob("*.md")):
    print(f"--- {path} ---")
    for number, line in enumerate(path.read_text().splitlines(), 1):
        if terms.search(line):
            print(f"{number}: {line}")
print("--- capability check ---")
text = "\n".join(path.read_text() for path in root.glob("*.md")).lower()
for phrase in (
    "update every",
    "update all",
    "bulk update",
    "revoke every",
    "block every virtual key",
    "future mints",
    "existing keys",
):
    print(f"{phrase!r}: {phrase in text}")
PY

Repository: Agenta-AI/agenta

Length of output: 7962


Define policy-change semantics for active virtual keys.

The policy payload can change live, but each virtual key receives its grant and limits at mint time. State whether changes apply only to future mints, or define an operation that updates or blocks active bridge keys.

Comment on lines +189 to +192
An invited teammate is not a special case. They still sign up, and the signup path creates
their own organization unless they already belong to one, so they are seeded exactly like
any other new signup. Nobody has to seed an organization twice, and nobody has to decide
what an invitation into a funded organization means.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

State invitation eligibility explicitly.

An invited teammate who joins an existing organization does not create a new organization. The sentence “they are seeded exactly like any other new signup” conflicts with the new-signups-only rule. State that only signups creating a new organization are eligible.

Comment on lines +227 to +235
## No repair path

Seeding does two writes that can fail independently: it mints a key at the proxy, then it
writes the vault row. A crash between them leaves an organization with a live key that
nothing references.

The bridge handles that inline and then stops. If the row write fails, the service blocks
the just-minted key, so an orphaned grant can never be spent. Nothing retries later.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- design document context ---'
sed -n '180,260p' docs/design/starter-credits-bridge/design.md
printf '%s\n' '--- related bridge and block references ---'
rg -n -i 'block|orphan|repair|retry|expire|mint|vault' docs/design/starter-credits-bridge
printf '%s\n' '--- repository files near the design ---'
git ls-files | rg 'starter-credits|bridge|proxy|vault' | head -200

Repository: Agenta-AI/agenta

Length of output: 18012


🏁 Script executed:

#!/bin/bash
set -e
for f in $(git ls-files 'api/ee/src/core/starter_credits_bridge/*' | sort); do
  printf '\n--- %s ---\n' "$f"
  wc -l "$f"
  ast-grep outline "$f" 2>/dev/null || true
done
printf '\n--- bridge symbols and call sites ---\n'
rg -n -i 'block|generate|mint|seed|vault|starter_credits_bridge|provision_signup_subscription' \
  api/ee/src api/ee/tests 2>/dev/null | head -300

Repository: Agenta-AI/agenta

Length of output: 11363


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- signup provisioning implementation ---'
sed -n '900,990p' api/ee/src/core/organizations/service.py
printf '%s\n' '--- bridge-related files discovered by content search ---'
rg -l -i 'starter.?credits|proxy admin|virtual key|seeded connection|PROXY_ADMIN_URL' api docs \
  -g '*.py' -g '*.md' -g '*.yaml' -g '*.yml' | sort
printf '%s\n' '--- repository state and recent file summary ---'
git status --short
git diff --stat

Repository: Agenta-AI/agenta

Length of output: 3206


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- proxy contract ---'
cat -n docs/design/starter-credits-bridge/proxy-and-deployment.md | sed -n '1,90p'
printf '%s\n' '--- design failure, timeout, alert, and teardown sections ---'
cat -n docs/design/starter-credits-bridge/design.md | sed -n '1,75p;120,180p;260,350p'
printf '%s\n' '--- all documented proxy operation contracts ---'
rg -n -C 3 -i 'block|unblock|timeout|alert|failure|retry|expiry|idempot|generate|mint|live|spend' \
  docs/design/starter-credits-bridge/*.md

Repository: Agenta-AI/agenta

Length of output: 50372


🏁 Script executed:

#!/bin/bash
set -e
python3 - <<'PY'
from pathlib import Path

design = Path("docs/design/starter-credits-bridge/design.md").read_text()
proxy = Path("docs/design/starter-credits-bridge/proxy-and-deployment.md").read_text()
readme = Path("docs/design/starter-credits-bridge/README.md").read_text()

required = [
    "mints a key at the proxy",
    "writes the vault row",
    "blocks the just-minted key",
    "Nothing retries later",
    "Mint succeeds, vault write fails",
]
for text in required:
    assert text in design, f"missing design contract: {text!r}"

section = design.split("## No repair path", 1)[1].split("## ", 1)[0].lower()
for term in ("retry", "repair", "expiry", "expire", "transaction"):
    print(f"{term}: {term in section}")

print("block capability:", "Block and unblock a key" in proxy)
print("failure alert documented:", "operator alert" in readme.lower())
print("failure-table behavior:")
for line in design.splitlines():
    if "Mint succeeds, vault write fails" in line:
        print(line)
PY

Repository: Agenta-AI/agenta

Length of output: 298


🏁 Script executed:

#!/bin/bash
set -e
python3 - <<'PY'
from pathlib import Path
import re

def normalized(path):
    return re.sub(r"\s+", " ", Path(path).read_text()).strip()

design = normalized("docs/design/starter-credits-bridge/design.md")
proxy = normalized("docs/design/starter-credits-bridge/proxy-and-deployment.md")
readme = normalized("docs/design/starter-credits-bridge/README.md")

required = [
    "mints a key at the proxy",
    "writes the vault row",
    "blocks the just-minted key",
    "Nothing retries later",
    "Mint succeeds, vault write fails",
]
for text in required:
    assert text in design, f"missing design contract: {text!r}"

start = design.index("## No repair path")
end = design.find("## ", start + len("## No repair path"))
section = design[start:end if end != -1 else None].lower()

for term in ("retry", "repair", "expiry", "expire", "transaction"):
    print(f"{term}: {term in section}")

print("block capability:", "Block and unblock a key" in proxy)
print("failure alert documented:", "operator alert" in readme.lower())
marker = "Mint succeeds, vault write fails"
pos = design.index(marker)
print("failure-table behavior:", design[pos:design.find("|", pos + len(marker))])
PY

Repository: Agenta-AI/agenta

Length of output: 339


Define failure handling for the compensating block call.

If the vault write fails while the proxy is unavailable, the key can remain spendable after recovery without a vault row. Define bounded retries with an operator alert, or require proxy-side expiry or transactional issuance.

Comment on lines +280 to +293
## Exhaustion is a product moment, not an error

When the organization's spend reaches the grant, the proxy refuses the call at admission
with HTTP 429. So does a per-key rate limit, and so does an upstream provider quota error.
Only the response body separates them.

The runner therefore classifies on the body, never on the status alone, and returns a
stable code alongside the human line (`RunErrorCode` in
`services/runner/src/engines/sandbox_agent/errors.ts`):
`starter_credits_exhausted`, `starter_credits_program_paused`,
`starter_credits_unavailable`, `rate_limited`, and `runner_error` for everything else. A
client can render a purposeful state from the code instead of parsing prose. Telling
someone their credits are gone when they were merely throttled is worse than saying
nothing, which is why the classification is narrow.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- candidate files ---'
git ls-files | rg '(^|/)(design\.md|errors\.ts|sandbox_agent|starter.?credits|proxy|runner)' | head -200
printf '%s\n' '--- relevant symbols and text ---'
rg -n -S 'RunErrorCode|starter_credits_exhausted|starter_credits_program_paused|starter_credits_unavailable|rate_limited|response body|429|credits exhausted|program paused' . --glob '!node_modules' --glob '!dist' --glob '!build' | head -300

Repository: Agenta-AI/agenta

Length of output: 50373


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- exact tracked paths ---'
git ls-files 'docs/design/starter-credits-bridge/design.md' 'services/runner/src/engines/sandbox_agent/errors.ts'
printf '%s\n' '--- design section ---'
sed -n '260,310p' docs/design/starter-credits-bridge/design.md
printf '%s\n' '--- runner error module ---'
wc -l services/runner/src/engines/sandbox_agent/errors.ts
cat -n services/runner/src/engines/sandbox_agent/errors.ts
printf '%s\n' '--- bounded tracked text search ---'
git grep -n -I -E 'RunErrorCode|starter_credits_exhausted|starter_credits_program_paused|starter_credits_unavailable|rate_limited' -- \
  '*.ts' '*.tsx' '*.js' '*.jsx' '*.py' '*.go' '*.rs' '*.md' '*.yaml' '*.yml' '*.json' \
  ':!*.lock' | head -300

Repository: Agenta-AI/agenta

Length of output: 9022


🏁 Script executed:

#!/bin/bash
set -eu
python3 - <<'PY'
import subprocess
from pathlib import Path

paths = subprocess.check_output(["git", "ls-files", "-z"], text=False).split(b"\0")
text_paths = []
for raw in paths:
    if not raw:
        continue
    p = Path(raw.decode())
    if p.suffix.lower() in {".ts", ".tsx", ".js", ".jsx", ".py", ".go", ".rs",
                            ".md", ".yaml", ".yml", ".json"}:
        text_paths.append(p)

terms = [
    "RunErrorCode",
    "starter_credits_exhausted",
    "starter_credits_program_paused",
    "starter_credits_unavailable",
    "rate_limited",
]
for term in terms:
    hits = []
    for p in text_paths:
        try:
            data = p.read_text()
        except (UnicodeDecodeError, OSError):
            continue
        for lineno, line in enumerate(data.splitlines(), 1):
            if term in line:
                hits.append(f"{p}:{lineno}:{line.strip()}")
    print(f"--- {term}: {len(hits)} occurrence(s) ---")
    print("\n".join(hits[:100]))

print("--- likely runner tests ---")
for p in text_paths:
    s = str(p).lower()
    if ("runner" in s or "sandbox_agent" in s) and ("test" in s or "spec" in s):
        print(p)
PY

Repository: Agenta-AI/agenta

Length of output: 11069


Define and implement the proxy-to-runner error contract.

The cited errors.ts file only defines conciseError; no implementation or test defines the listed RunErrorCode values. Specify the proxy-owned JSON discriminator, exact values, ownership, fallback behavior, and end-to-end tests for HTTP 429 classification.

Comment on lines +76 to +84
## The seeded URL must be HTTPS

`effective_endpoint` rejects any connection base URL that is not absolute HTTPS
(`sdks/python/agenta/sdk/agents/connections/endpoints.py`, "model connection endpoint must
be an absolute HTTPS URL"). There is no override and no local exception.

This is a real constraint on local development. A proxy on `http://localhost` cannot be
seeded, because the resolver refuses the connection before any call is made. Put a
tunnel with a real certificate in front of it, and seed the tunnel's URL.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Document all endpoint-validation constraints.

This section says only “absolute HTTPS.” The downstream validator in services/runner/src/engines/sandbox_agent/daytona-secret-plan.ts:161-211 also rejects IP literals, local or internal hosts, wildcard hosts, non-default ports, credentials, and fragments, and requires a normalized public DNS hostname. List these constraints or link to the validator.

Comment on lines +57 to +72
Every variable is read once into `StarterCreditsBridgeConfig`
(`api/oss/src/utils/env.py`). The bridge is `armed` only when `ENABLED` is true and both
proxy addresses, the master key, and the team id are all present. An unarmed deployment
returns from the seeding call immediately, which is what every OSS and self-hosted
deployment does.

| Variable (`AGENTA_STARTER_CREDITS_BRIDGE_` prefix) | Required to arm | What it holds |
| --- | --- | --- |
| `ENABLED` | yes | The opt-in switch. Defaults to false. Changing it takes a redeploy |
| `PROXY_PUBLIC_URL` | yes | The base URL stored on the seeded connection. A sandboxed run dials it from outside the deployment's network, so only the proxy's inference paths are published there |
| `PROXY_ADMIN_URL` | yes | The proxy's address on the private network. The minting client dials it, so the master key never crosses the public edge |
| `MASTER_KEY` | yes | The proxy's admin credential. It mints and blocks keys |
| `TEAM_ID` | yes | The proxy team every minted key joins. The team's own budget ceiling bounds total exposure, so seeding refuses to run without one |
| `MODEL_ID` | no | The single model id the minted key allowlists and the seeded connection publishes. Defaults to `vertex_ai/gemini-3.6-flash` |
| `POLICY_FLAG` | no | The name of the PostHog feature flag whose payload carries the mint policy. Defaults to `starter-credits-bridge-policy` |
| `ALERT_WEBHOOK` | no | An operator webhook. The service posts `{"text": ...}` to it on refusals and failures |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- candidate files ---'
git ls-files | rg '(^|/)(README\.md|design\.md|env\.py)$|starter-credits-bridge'
printf '%s\n' '--- relevant references ---'
rg -n -C 5 'StarterCreditsBridgeConfig|AGENTA_STARTER_CREDITS_BRIDGE|development policy|PostHog|POLICY_FLAG|seed' docs api/oss/src 2>/dev/null | head -n 500

Repository: Agenta-AI/agenta

Length of output: 50373


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- bridge files ---'
git ls-files | rg 'starter-credits-bridge|api/oss/src/utils/env\.py$'
printf '%s\n' '--- README excerpt ---'
sed -n '1,130p' docs/design/starter-credits-bridge/README.md
printf '%s\n' '--- design policy excerpt ---'
sed -n '120,180p' docs/design/starter-credits-bridge/design.md
printf '%s\n' '--- configuration and environment references ---'
rg -n -C 8 --glob '*.py' --glob '*.md' --glob '*.yaml' --glob '*.yml' --glob '*.toml' \
  'StarterCreditsBridgeConfig|AGENTA_STARTER_CREDITS_BRIDGE|development policy|POSTHOG|ENVIRONMENT|environment' \
  docs/design/starter-credits-bridge api/oss/src

Repository: Agenta-AI/agenta

Length of output: 50373


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- exact bridge paths ---'
find docs/design/starter-credits-bridge api/oss/src -maxdepth 8 -type f \( -name 'README.md' -o -name 'design.md' -o -name 'env.py' \) -print
printf '%s\n' '--- README lines 1-100 ---'
sed -n '1,100p' docs/design/starter-credits-bridge/README.md
printf '%s\n' '--- design lines 130-170 ---'
sed -n '130,170p' docs/design/starter-credits-bridge/design.md
printf '%s\n' '--- exact bridge symbol matches ---'
rg -n -C 10 --glob '*.py' 'StarterCreditsBridgeConfig|AGENTA_STARTER_CREDITS_BRIDGE' api/oss/src
printf '%s\n' '--- policy fallback matches in bridge docs ---'
rg -n -C 8 'development policy|PostHog|POLICY_FLAG|policy key|feature flag' docs/design/starter-credits-bridge

Repository: Agenta-AI/agenta

Length of output: 9059


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- bridge implementation files ---'
find api/ee/src/core/starter_credits_bridge api/oss/src -maxdepth 5 -type f 2>/dev/null | sort | head -n 100
printf '%s\n' '--- bridge symbol search across tracked source ---'
rg -n -C 6 --hidden --glob '!*.json' --glob '!*.lock' \
  'StarterCreditsBridgeConfig|AGENTA_STARTER_CREDITS_BRIDGE|seed_starter_credits_bridge|development_policy|built-in development policy' .
printf '%s\n' '--- policy section ---'
rg -n -C 12 'The mint policy|PostHog key|no PostHog|development policy|configured no' docs/design/starter-credits-bridge/design.md
printf '%s\n' '--- env PostHog fields ---'
rg -n -C 8 --glob 'env.py' 'POSTHOG|posthog|environment|deployment' api/oss/src/utils/env.py

Repository: Agenta-AI/agenta

Length of output: 26044


🏁 Script executed:

#!/bin/bash
set -e
python3 - <<'PY'
from pathlib import Path
import re

readme = Path("docs/design/starter-credits-bridge/README.md").read_text()
design = Path("docs/design/starter-credits-bridge/design.md").read_text()
env = Path("api/oss/src/utils/env.py").read_text()

required = set(re.findall(r"\| `([^`]+)` \| yes \|", readme))
assert required == {"ENABLED", "PROXY_PUBLIC_URL", "PROXY_ADMIN_URL", "MASTER_KEY", "TEAM_ID"}

fallback = re.search(
    r"\| The deployment configured no PostHog key of its own \| ([^\n]+)",
    design,
)
assert fallback and "built-in development policy" in fallback.group(1)

posthog_block = env[env.index("class PostHogConfig"):env.index("class EnvironSettings")]
assert 'or "https://alef.agenta.ai"' in posthog_block
assert 'or "phc_hmVSxIjTW1REBHXgj2aw4HW9X6CXb6FzerBgP9XenC7"' in posthog_block

print("arming variables:", ", ".join(sorted(required)))
print("missing from arming variables: POSTHOG_API_KEY")
print("no-own-key policy result:", fallback.group(1))
print("PostHog fallback: built-in api_url and built-in api_key")
PY

Repository: Agenta-AI/agenta

Length of output: 403


Require an explicit non-production guard for the development policy.

ENABLED arms the bridge without POSTHOG_API_KEY. A missing deployment-owned key selects the built-in development policy, and PostHogConfig supplies a built-in key when the environment variable is absent. Add an explicit non-production condition or require a deployment-owned policy source before arming.

@mmabrouk
mmabrouk changed the base branch from main to release/v0.114.0 August 22, 2026 18:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant