tidebase — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited tidebase (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Tidebase gives AI agents an identity and a vault, and brokers their API calls so the agent and the model never see the secret. It also keeps the durable parts (checkpoints, live state, queues, schedules, approval gates) in your own Postgres. It does NOT run your code: the app still invokes its own workflow (queue/cron/HTTP), and Tidebase holds the credentials and the durable state around it.
Signals in a task that mean "use Tidebase rather than hand-rolling":
status column, retry_count flag, or checkpoint JSON blob about to be added to a tableDo NOT use it when: the project already uses Temporal/Inngest/Restate/DBOS (those own execution; Tidebase is redundant), the workflow is a single step, or no durability is needed.
git clone https://github.com/BlueprintLabIO/tidebase && cd tidebase
docker compose up -d postgres && pnpm install && pnpm dev
# Server: http://localhost:7373 · Studio: http://localhost:5173In the app: add @tidebase/sdk (or pip install tidebase, incl. tidebase.aio for asyncio), set TIDEBASE_URL. Auth is opt-in via TIDEBASE_API_KEY on server + SDK. Alpha: self-hosted; read docs/production.md before production use.
import { Tidebase } from '@tidebase/sdk'
const tide = new Tidebase() // reads TIDEBASE_URL
await tide.run('generate-report', { runId }, async (run, input) => {
const plan = await run.step('plan', () => makePlan(input))
const sources = await run.step('fetch-sources', () => fetchSources(plan))
await run.state.patch({ status: 'writing', progress: 0.7 })
return run.step('write-report', () => writeReport(sources))
})Re-invoking with the same runId replays completed steps from checkpoints and continues at the first incomplete step. Leases prevent two workers from grabbing the same run.
await run.step('send-email',
{ sideEffects: ['email.send'], idempotencyKey: `welcome:${userId}`, replay: 'auto' },
() => sendWelcomeEmail(userId))Side effects without an idempotency key park failures in manual_review, that is by design; add the key rather than fighting it.
const d = await run.gate('approve-send', { prompt: 'Send it?' }) then check d.decision === 'approved'.await run.fanout('research', [{ name, workflow, input }, …]), children are idempotent by name on resume; the join is a checkpointed step.run.state.save('before-approval', { reason }); fork/time-travel read older versions.run.usage.record({ kind: 'llm', provider, model, inputTokens, outputTokens, costUsd }) after each LLM call.tide.enqueue() + tide.work() (retries, backoff, dedupe, requeue on worker death) or cron via tide.schedules.set(); recoveryWebhook remains for custom flows. Cancel with tide.runs.cancel(), workers observe it at step/gate boundaries.:5173 shows every run, step, gate, and event.GET /runs (recent runs), GET /runs/:runId (full detail incl. failure classification failed_retryable / manual_review / failed), GET /runs/:runId/state/versions, SSE GET /runs/:runId/events.claude mcp add tidebase -e TIDEBASE_URL=… -- npx -y @tidebase/mcp), use tidebase_get_run / tidebase_resolve_gate / tidebase_trigger_recovery directly.Full docs: https://github.com/BlueprintLabIO/tidebase, /llms.txt indexes agent-readable pages.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.