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
23 changes: 23 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,17 @@ commands:
done < "${env_file}"

jobs:
pr-status:
docker:
- image: cimg/base:stable
steps:
- run:
name: CircleCI is release-only
command: |
set -euo pipefail
echo "CircleCI release jobs run only on rust-v* tags."
echo "Pull-request merge gating lives in GitHub Actions."

tag-check:
docker:
- image: cimg/base:stable
Expand All @@ -105,6 +116,14 @@ jobs:
echo "tag ${tag_ver} does not match Cargo.toml ${cargo_ver}"
exit 1
fi
- run:
name: DB sandbox release smoke
command: |
set -euo pipefail
scripts/probes/check-db-sandbox-readiness.sh --dry-run
scripts/probes/check-db-sandbox-readiness.sh --source-provider neon --branch-backend none --include-branch-lifecycle --dry-run
scripts/probes/check-db-sandbox-readiness.sh --source-provider planetscale --branch-backend none --dry-run
python3 -c 'import json; schema = json.load(open("thinwedge-rs/core/config.schema.json", encoding="utf-8")); props = schema.get("properties", {}); assert "db_sandbox" in props, "config schema must expose db_sandbox"; assert "ardent" in props, "config schema must keep optional Ardent settings"'

build-linux-x64:
machine:
Expand Down Expand Up @@ -563,6 +582,10 @@ jobs:
workflows:
release:
jobs:
- pr-status:
filters:
tags:
ignore: /.*/
- tag-check:
filters:
branches:
Expand Down
14 changes: 14 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,20 @@ jobs:
- name: Check public release readiness blockers
run: python3 scripts/check_public_release_readiness.py

- name: DB sandbox release smoke
run: |
set -euo pipefail
scripts/probes/check-db-sandbox-readiness.sh --dry-run
scripts/probes/check-db-sandbox-readiness.sh --source-provider neon --branch-backend none --include-branch-lifecycle --dry-run
scripts/probes/check-db-sandbox-readiness.sh --source-provider planetscale --branch-backend none --dry-run
python3 - <<'PY'
import json
schema = json.load(open("thinwedge-rs/core/config.schema.json", encoding="utf-8"))
props = schema.get("properties", {})
assert "db_sandbox" in props, "config schema must expose db_sandbox"
assert "ardent" in props, "config schema must keep optional Ardent settings"
PY

- name: Setup pnpm
uses: pnpm/action-setup@a8198c4bff370c8506180b035930dea56dbd5288 # v5
with:
Expand Down
39 changes: 37 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ npm install -g @never2average-does-npm/cli

Authenticate before starting interactive mode. In a real terminal, `thinwedge login`
prompts for the required OpenRouter-compatible API token and optional capability
config such as Artificial Analysis, RunPod, and AWS profile/region values:
config such as Artificial Analysis, RunPod, AWS profile/region values, and Neon
DB sandbox metadata:

```shell
thinwedge login
Expand All @@ -24,6 +25,8 @@ thinwedge login
# RUNPOD_API_KEY (...) [optional]: ...
# AWS_PROFILE (...) [optional]: ...
# AWS_REGION (...) [optional]: ...
# THINWEDGE_NEON_API_KEY (...) [optional]: ...
# THINWEDGE_NEON_PROJECT_ID (...) [optional]: ...
```

Or set the provider token in the environment first:
Expand Down Expand Up @@ -61,6 +64,7 @@ The product surface is intentionally local-first:
- `thinwedge` starts the interactive terminal UI.
- `thinwedge exec` runs a single non-interactive agent task.
- `thinwedge login` stores an OpenRouter-compatible API token locally.
- `thinwedge db-sandbox` configures and preflights DB sandbox providers.
- `THINWEDGE_HOME` controls where config, auth, logs, thread history, and local state live.

## System Components
Expand Down Expand Up @@ -97,7 +101,8 @@ ThinWedge uses API-token authentication. Run `thinwedge login` before starting
the interactive TUI so the agent can call the configured provider API. In a real
terminal, `thinwedge login` behaves like an `aws configure`-style prompt: it asks
for the required OpenRouter-compatible API token, then offers optional prompts for
`ARTIFICIAL_ANALYSIS_API_KEY`, `RUNPOD_API_KEY`, `AWS_PROFILE`, and `AWS_REGION`.
`ARTIFICIAL_ANALYSIS_API_KEY`, `RUNPOD_API_KEY`, `AWS_PROFILE`, `AWS_REGION`,
`THINWEDGE_NEON_API_KEY`, and `THINWEDGE_NEON_PROJECT_ID`.
The required provider token is stored in ThinWedge auth storage; optional capability
values are written to `THINWEDGE_HOME/.env`, which ThinWedge loads on startup.

Expand All @@ -108,6 +113,8 @@ thinwedge login
# RUNPOD_API_KEY (...) [optional]: ...
# AWS_PROFILE (...) [optional]: ...
# AWS_REGION (...) [optional]: ...
# THINWEDGE_NEON_API_KEY (...) [optional]: ...
# THINWEDGE_NEON_PROJECT_ID (...) [optional]: ...
```

You can also provide the provider token through the environment:
Expand Down Expand Up @@ -143,6 +150,34 @@ coordination model:
into real workbook sheets.
- `/status`, `/diff`, `/permissions`, `/mcp`, `/skills`, `/apps`, and `/plugins` expose runtime, workspace, and integration state.

## DB Sandbox Setup

Finance agents should not run migrations or experiments directly against
production state. ThinWedge models this as a provider-first setup: validate a
source provider, then hand agents only disposable database state.

Neon is the default path:

```shell
thinwedge db-sandbox configure --enabled --provider neon --neon-project-id <project-id> --branch-backend none
thinwedge db-sandbox preflight --dry-run
thinwedge db-sandbox preflight --provider neon
```

Ardent is optional. Use it as the branch backend only after the Neon or Postgres
source checks pass:

```shell
thinwedge db-sandbox configure --branch-backend ardent
thinwedge ardent status --dry-run
```

The bottom-up source of truth is still the probe scripts:

```shell
scripts/probes/check-db-sandbox-readiness.sh --source-provider neon --branch-backend none
```

## Logical Tool Tree

ThinWedge organizes tools in layers so the agent can reason about local execution,
Expand Down
47 changes: 35 additions & 12 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,11 @@ The generated JSON Schema for `config.toml` lives at `thinwedge-rs/core/config.s

## Finance DB sandboxing

ThinWedge can keep finance/database agents away from production state by using an
Ardent Postgres branch as the task database. The CLI integration is optional:
`thinwedge login` can offer to configure it, and explicit `thinwedge ardent ...`
commands can manage it directly.
ThinWedge can keep finance/database agents away from production state by first
validating a source provider, then handing agents only disposable sandbox
database state. Neon is the default provider path because it can be checked from
a Postgres URL plus Neon API metadata. Ardent remains optional: use it when you
want an external branch backend after the source provider is proven.

The non-secret configuration shape is:

Expand All @@ -90,6 +91,15 @@ aws_profile = "fpna-db-ops"
role_arn = "arn:aws:iam::123456789012:role/fpna-db-ops"
region = "us-west-2"

[db_sandbox]
enabled = true
provider = "neon"
source_url_env = "THINWEDGE_ARDENT_SOURCE_DATABASE_URL"
neon_api_key_env = "THINWEDGE_NEON_API_KEY"
neon_project_id_env = "THINWEDGE_NEON_PROJECT_ID"
neon_project_id = "twilight-lab-63846303"
branch_backend = "none"

[ardent]
enabled = true
cli_path = "ardent"
Expand All @@ -101,13 +111,17 @@ data_plane = "byoc"

Use `aws_profile` for local workstation setup. Production deployments should
prefer role-based or managed credential providers that resolve to narrowly scoped
AWS credentials. Source database URLs and Ardent branch URLs are not config
values; source credentials should come from secure stores, and agents should only
receive a branch `DATABASE_URL`.
AWS credentials. Source database URLs, API keys, and branch URLs are not config
values; they should come from secure stores or environment variables. Agents
should only receive disposable branch or sandbox `DATABASE_URL` values.

Useful CLI entry points:

```bash
thinwedge db-sandbox status
thinwedge db-sandbox configure --enabled --provider neon --neon-project-id <neon-project-id> --branch-backend none --dry-run
thinwedge db-sandbox preflight --dry-run
thinwedge db-sandbox preflight --provider neon
thinwedge ardent status --dry-run
thinwedge ardent login --dry-run
thinwedge ardent configure --enabled --billing-profile fpna-billing --billing-role-arn arn:aws:iam::123456789012:role/fpna-billing --db-ops-profile fpna-db-ops --db-ops-role-arn arn:aws:iam::123456789012:role/fpna-db-ops --connector fpna-prod --data-plane byoc --dry-run --no-prompt
Expand All @@ -117,6 +131,12 @@ thinwedge ardent branch create --connector fpna-prod --name thinwedge-agent-test
thinwedge ardent branch delete thinwedge-agent-test --connector fpna-prod --dry-run
```

`thinwedge db-sandbox configure` stores only non-secret provider metadata. The
interactive `thinwedge login` flow offers the same setup after the OpenRouter API
token and optional capability prompts. `branch_backend = "none"` is the default
for provider-only validation; switch it to `"ardent"` only after deciding Ardent
should manage disposable database branches.

`thinwedge ardent connector create` is intentionally mutation-gated for live runs
because it attaches a production source database to Ardent. Pass
`--allow-mutation` only after that blast radius is approved. The source URL is
Expand All @@ -128,8 +148,10 @@ Choosing `managed` versus `byoc` for `ardent.data_plane` is also an explicit
deployment-boundary decision; record that choice during setup instead of treating
it as an automatic default.

Validate the external contracts bottom-up before trusting the integration. Start
with dry-run wiring:
Validate the external contracts bottom-up before trusting the integration. This
is the production-scale workflow for a technical CFO/operator: bring a source DB
URL/API key, run preflight, and only then allow agents to use disposable DB
state. Start with dry-run wiring:

```bash
scripts/probes/check-db-sandbox-readiness.sh --dry-run
Expand All @@ -145,13 +167,14 @@ set -a
. scripts/probes/db-sandbox-readiness.env
set +a

scripts/probes/check-db-sandbox-readiness.sh
scripts/probes/check-db-sandbox-readiness.sh --source-provider neon --branch-backend none
```

Live branch creation/deletion is mutation-gated and requires explicit opt-in:
Live branch creation/deletion is mutation-gated and requires explicit opt-in.
Use this only when `branch_backend = "ardent"` is part of the deployment:

```bash
TW_PROBE_ALLOW_MUTATION=1 scripts/probes/check-ardent-branch-lifecycle.sh
TW_PROBE_ALLOW_MUTATION=1 scripts/probes/check-db-sandbox-readiness.sh --source-provider neon --branch-backend ardent --include-branch-lifecycle --allow-mutation
```

For Neon, validate the source and Neon API before attempting Ardent BYOC setup:
Expand Down
17 changes: 9 additions & 8 deletions scripts/probes/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# ThinWedge Probe Scripts

These scripts validate external integration contracts before the Rust CLI is rebuilt. They are intentionally bottom-up so AWS billing, AWS DB Ops, source database readiness, Ardent auth, connector readiness, and branch lifecycle can be tested independently.
These scripts validate external integration contracts before the Rust CLI is rebuilt. They are intentionally bottom-up so provider readiness, optional AWS billing, optional AWS DB Ops, optional Ardent auth, connector readiness, and branch lifecycle can be tested independently.

All probes support `--dry-run` for cheap syntax and wiring checks. Live runs require the relevant AWS, Neon, database, and Ardent credentials in the current shell. Set `THINWEDGE_DB_SECRET_ID` or `THINWEDGE_DB_SSM_PARAMETER` to verify a specific DB connection secret. RDS readiness live runs require TCP reachability from the current host and `THINWEDGE_DB_ROLE_DATABASE_URL` for the DB setup role check. Generic Postgres, Supabase, and Neon readiness live runs require `THINWEDGE_ARDENT_SOURCE_DATABASE_URL`.
All probes support `--dry-run` for cheap syntax and wiring checks. Live runs require the relevant provider credentials in the current shell. Neon is the default provider path; Ardent is checked only when `--branch-backend ardent` or `THINWEDGE_DB_SANDBOX_BRANCH_BACKEND=ardent` is set. Set `THINWEDGE_DB_SECRET_ID` or `THINWEDGE_DB_SSM_PARAMETER` to verify a specific DB connection secret. RDS readiness live runs require TCP reachability from the current host and `THINWEDGE_DB_ROLE_DATABASE_URL` for the DB setup role check. Generic Postgres, Supabase, and Neon readiness live runs require `THINWEDGE_ARDENT_SOURCE_DATABASE_URL`.

```bash
scripts/probes/check-aws-billing.sh --dry-run
Expand All @@ -18,15 +18,15 @@ scripts/probes/check-db-sandbox-readiness.sh --dry-run
Live validation expects the shell to already have:

- an AWS CLI on `PATH`
- a billing AWS identity with STS, Cost Explorer, CUR, Budgets, and IAM account-summary read access, via `THINWEDGE_BILLING_AWS_PROFILE` or `AWS_PROFILE`
- a DB Ops AWS identity, via `THINWEDGE_DB_OPS_AWS_PROFILE` or `AWS_PROFILE`
- a billing AWS identity with STS, Cost Explorer, CUR, Budgets, and IAM account-summary read access, via `THINWEDGE_BILLING_AWS_PROFILE` or `AWS_PROFILE`, when running billing checks
- a DB Ops AWS identity, via `THINWEDGE_DB_OPS_AWS_PROFILE` or `AWS_PROFILE`, when running RDS or DB Ops checks
- `nc` for RDS TCP reachability checks
- `psql` plus `THINWEDGE_DB_ROLE_DATABASE_URL` for RDS DB setup role validation
- `psql` plus `THINWEDGE_ARDENT_SOURCE_DATABASE_URL` for generic Postgres, Supabase, and Neon source validation
- a Neon API key and project id in `THINWEDGE_NEON_API_KEY` and `THINWEDGE_NEON_PROJECT_ID` when `THINWEDGE_DB_SOURCE_PROVIDER=neon`
- an authenticated Ardent CLI from `ardent login`
- a selected Ardent project from `ardent project switch <name>`
- at least one Ardent connector; set `THINWEDGE_ARDENT_CONNECTOR` to verify the intended connector
- an authenticated Ardent CLI from `ardent login`, only when using `--branch-backend ardent`
- a selected Ardent project from `ardent project switch <name>`, only when using `--branch-backend ardent`
- at least one Ardent connector; set `THINWEDGE_ARDENT_CONNECTOR` to verify the intended connector, only when using `--branch-backend ardent`

Run the non-mutating live checks before trusting a finance DB sandbox setup:

Expand All @@ -37,14 +37,15 @@ set -a
. scripts/probes/db-sandbox-readiness.env
set +a

scripts/probes/check-db-sandbox-readiness.sh --source-provider neon --branch-backend none
scripts/probes/check-aws-billing.sh
scripts/probes/check-aws-db-ops.sh
scripts/probes/check-rds-postgres-readiness.sh --db-instance <rds-postgres-instance>
THINWEDGE_DB_SOURCE_PROVIDER=postgresql scripts/probes/check-postgres-source-readiness.sh
THINWEDGE_DB_SOURCE_PROVIDER=neon scripts/probes/check-neon-postgres-readiness.sh
scripts/probes/check-ardent-auth.sh
scripts/probes/check-ardent-connector.sh --connector <ardent-connector-name>
scripts/probes/check-db-sandbox-readiness.sh
scripts/probes/check-db-sandbox-readiness.sh --source-provider neon --branch-backend ardent
```

The RDS readiness probe fails live unless it can prove network reachability and
Expand Down
56 changes: 42 additions & 14 deletions scripts/probes/check-db-sandbox-readiness.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

usage() {
cat <<'EOF'
Usage: check-db-sandbox-readiness.sh [--source-provider rds|postgresql|supabase|neon] [--dry-run] [--include-branch-lifecycle] [--allow-mutation]
Usage: check-db-sandbox-readiness.sh [--source-provider neon|postgresql|rds|supabase|planetscale] [--branch-backend none|ardent] [--dry-run] [--include-branch-lifecycle] [--allow-mutation]

Runs the bottom-up readiness probes for ThinWedge finance DB sandboxing. By
default it avoids mutation-gated Ardent branch creation. Use both
default it validates Neon provider readiness without requiring Ardent. Use
--branch-backend ardent to add Ardent auth/connector checks. Use both
--include-branch-lifecycle and --allow-mutation after explicit approval to create
and delete a temporary Ardent branch.
and delete a temporary provider or backend branch.

Common env vars:
THINWEDGE_DB_SOURCE_PROVIDER
THINWEDGE_DB_SANDBOX_BRANCH_BACKEND
THINWEDGE_BILLING_AWS_PROFILE
THINWEDGE_DB_OPS_AWS_PROFILE
THINWEDGE_RDS_DB_INSTANCE
Expand All @@ -27,10 +29,12 @@ EOF
dry_run=0
include_branch_lifecycle=0
allow_mutation=0
source_provider="${THINWEDGE_DB_SOURCE_PROVIDER:-rds}"
source_provider="${THINWEDGE_DB_SOURCE_PROVIDER:-neon}"
branch_backend="${THINWEDGE_DB_SANDBOX_BRANCH_BACKEND:-none}"
while [[ $# -gt 0 ]]; do
case "$1" in
--source-provider) source_provider="${2:?missing source provider}"; shift 2 ;;
--branch-backend) branch_backend="${2:?missing branch backend}"; shift 2 ;;
--dry-run) dry_run=1; shift ;;
--include-branch-lifecycle) include_branch_lifecycle=1; shift ;;
--allow-mutation) allow_mutation=1; shift ;;
Expand All @@ -44,9 +48,19 @@ args=()
mutation_args=()
[[ "${dry_run}" == "1" ]] && mutation_args+=(--dry-run)
[[ "${allow_mutation}" == "1" ]] && mutation_args+=(--allow-mutation)
neon_args=("${mutation_args[@]}")
[[ "${include_branch_lifecycle}" == "1" ]] && neon_args+=(--include-api-branch-smoke)

"${SCRIPT_DIR}/check-aws-billing.sh" "${args[@]}"
"${SCRIPT_DIR}/check-aws-db-ops.sh" "${args[@]}"
if [[ -n "${THINWEDGE_BILLING_AWS_PROFILE:-}" || -n "${THINWEDGE_BILLING_ROLE_ARN:-}" ]]; then
"${SCRIPT_DIR}/check-aws-billing.sh" "${args[@]}"
else
echo '[thinwedge-probe] skipping AWS billing probe; no billing AWS identity env configured'
fi
if [[ "${source_provider}" == "rds" || -n "${THINWEDGE_DB_OPS_AWS_PROFILE:-}" || -n "${THINWEDGE_DB_OPS_ROLE_ARN:-}" ]]; then
"${SCRIPT_DIR}/check-aws-db-ops.sh" "${args[@]}"
else
echo '[thinwedge-probe] skipping AWS DB Ops probe; provider does not require AWS DB Ops env'
fi
case "${source_provider}" in
rds)
"${SCRIPT_DIR}/check-rds-postgres-readiness.sh" "${args[@]}"
Expand All @@ -55,7 +69,10 @@ case "${source_provider}" in
"${SCRIPT_DIR}/check-postgres-source-readiness.sh" "${mutation_args[@]}"
;;
neon)
"${SCRIPT_DIR}/check-neon-postgres-readiness.sh" "${mutation_args[@]}"
"${SCRIPT_DIR}/check-neon-postgres-readiness.sh" "${neon_args[@]}"
;;
planetscale)
echo '[thinwedge-probe] PlanetScale provider selected; live PlanetScale probe is not available yet'
;;
none|skip)
echo '[thinwedge-probe] skipping source database readiness probe by explicit provider'
Expand All @@ -65,11 +82,22 @@ case "${source_provider}" in
exit 1
;;
esac
"${SCRIPT_DIR}/check-ardent-auth.sh" "${args[@]}"
"${SCRIPT_DIR}/check-ardent-connector.sh" "${args[@]}"
if [[ "${include_branch_lifecycle}" == "1" ]]; then
"${SCRIPT_DIR}/check-ardent-branch-lifecycle.sh" "${mutation_args[@]}"
else
echo '[thinwedge-probe] skipping mutation-gated Ardent branch lifecycle probe'
fi
case "${branch_backend}" in
none|skip)
echo '[thinwedge-probe] skipping branch backend probe by explicit backend'
;;
ardent)
"${SCRIPT_DIR}/check-ardent-auth.sh" "${args[@]}"
"${SCRIPT_DIR}/check-ardent-connector.sh" "${args[@]}"
if [[ "${include_branch_lifecycle}" == "1" ]]; then
"${SCRIPT_DIR}/check-ardent-branch-lifecycle.sh" "${mutation_args[@]}"
else
echo '[thinwedge-probe] skipping mutation-gated Ardent branch lifecycle probe'
fi
;;
*)
echo "unknown branch backend: ${branch_backend}" >&2
exit 1
;;
esac
echo '[thinwedge-probe] DB sandbox readiness probe suite passed'
Loading
Loading