Blink is a declarative deploy, test, rollback, and reporting CLI driven by blink.toml.
Today, the repo ships a working Ruby engine for:
- manifest validation and planning
- deploy and rollback pipelines
- local and SSH targets
- artifact fetching from
local_build,github_release, andurlsources - Ruby and declarative inline verification suites
- persisted
.blink/state, history, and artifact metadata - static report generation
- a current agent/tool server via
--mcp
This README documents the feature set that exists in the codebase now. Active unfinished work is tracked in the workspace root ROADMAP.md.
Generate a starter manifest:
bin/blink init --service appThat scaffold produces a local-target manifest shaped like this:
[blink]
version = "1"
[targets.local]
type = "local"
[services.app]
description = "Replace this with a short service description"
port = "3000"
[services.app.source]
type = "local_build"
command = "make build"
artifact = "dist/app"
[services.app.deploy]
target = "local"
pipeline = ["fetch_artifact", "stop", "install", "start", "health_check", "verify"]
rollback_pipeline = ["stop", "rollback", "start"]
[services.app.install]
dest = "/opt/app/app"
[services.app.stop]
command = "systemctl stop app"
[services.app.start]
command = "systemctl start app"
[services.app.health_check]
url = "http://127.0.0.1:{{port}}/health"
[services.app.verify]
tags = ["smoke"]Typical workflow:
bin/blink validate --json
bin/blink plan app --json
bin/blink deploy app --json
bin/blink test app --json
bin/blink state app --json
bin/blink history app --json
bin/blink report generate --format html --jsonCurrent top-level commands:
init: scaffold a starterblink.tomlvalidate: schema-check a manifest and report actionable errorsplan: expand a service into a resolved deploy plan with warnings and blockersdeploy: execute the declared pipeline and persist run historytest: run Ruby suites and/or declarative inline checksstatus: inspect service health on a targetdoctor: run connectivity and basic host health checkslogs: fetch or stream service logsrestart: restart a service using stop/start or restart commandsrollback: run the declared rollback pipelinesteps: inspect built-in step definitionsps: show Docker containers on a targetstate: read persisted.blinkstatehistory: read recent or specific recorded runsreport generate: write static HTML or JSON reports from.blinkhistoryssh: open an interactive SSH session to an SSH target
Most commands support --json. blink validate exits with code 2 for manifest validation errors.
Blink manifests are TOML with three core sections:
[blink]: manifest metadata[targets.<name>]: runtime environments[services.<name>]: service configuration, sources, steps, and verification
Parent manifests can also compose child manifests with blink.includes:
[blink]
version = "1"
includes = [
"BearClaw/blink.toml",
"BearClawWeb/blink.toml",
"Polar/blink.toml",
]
[targets.homelab]
type = "ssh"
host = "blink"
user = "admin"
[services.stack]
description = "Workspace-wide verification"
[services.stack.deploy]
target = "homelab"
pipeline = ["verify"]
[services.stack.verify.tests.edge]
type = "shell"
command = "echo ok"
expect_output = "ok"Included services keep resolving relative source paths, suite files, scripts, and build mounts against their child manifest directory. That lets a workspace root manifest import repo-local service manifests and still run blink test, blink build, blink plan, or blink deploy from the parent.
Minimal required shape:
[blink]
version = "1"
[targets.local]
type = "local"
[services.app.deploy]
target = "local"
pipeline = ["verify"]
[services.app.verify]
suite = "suite.rb"Blink currently resolves manifests by:
- explicit path argument when supported
BLINK_MANIFESTblink.tomlin the current directory or a parent directory~/.config/blink/blink.toml
A .env file in the manifest directory is also loaded when the manifest is read.
Supported target types today:
local: runs commands on the local machinessh: runs commands oversshand transfers files withscp
Target features currently implemented:
- optional
basedirectory - optional
envtable injected into target commands - target overrides with
--target
Example:
[targets.prod]
type = "ssh"
host = "prod.example.com"
user = "deploy"
base = "/srv/app"
[targets.prod.env]
RACK_ENV = "production"Supported source types today:
Runs a local docker run with bind-mounted workspace access, then stages or caches the host-side artifact.
[services.app.source]
type = "containerized_local_build"
image = "docker:cli"
mount = ".:/workspace"
workdir = "/workspace"
command = "docker buildx build --platform linux/amd64 --load -t app:local . && docker save app:local | gzip -c > dist/app-image.tar.gz"
artifact = "dist/app-image.tar.gz"
docker_socket = true
platform = "linux/amd64"
[services.app.source.env]
TARGET_PLATFORM = "linux/amd64"Optional fields:
envenv_fileplatformdocker_socketpullentrypointuser
mount accepts either a single host:container[:mode] string or an array of mount specs.
Runs a local build command, then stages or caches the artifact.
[services.app.source]
type = "local_build"
workdir = "."
command = "bin/build"
artifact = "dist/app.tar.gz"
[services.app.source.env]
GOOS = "linux"local_build also supports named builds under source.builds plus source.default.
Fetches a release asset from GitHub and caches it by tag and asset name.
[services.app.source]
type = "github_release"
repo = "owner/name"
asset = "app-linux-amd64.tar.gz"
token_env = "GITHUB_TOKEN"
sha256 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
checksum_asset = "checksums.txt"
signature_asset = "app-linux-amd64.tar.gz.minisig"
verify_command = "minisign -Vm {{artifact}} -x {{signature}} -P /path/to/minisign.pub"Supported integrity and provenance options:
- literal
sha256 - release
checksum_asset - release
signature_assetplusverify_command
Fetches an artifact from file://, http://, or https://.
[services.app.source]
type = "url"
url = "https://downloads.example.com/app-{{version}}.tar.gz"
artifact = "app.tar.gz"
token_env = "DOWNLOAD_TOKEN"
sha256 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
checksum_url = "https://downloads.example.com/app-{{version}}.sha256"
signature_url = "https://downloads.example.com/app-{{version}}.minisig"
verify_command = "minisign -Vm {{artifact}} -x {{signature}} -P /path/to/minisign.pub"
timeout_seconds = 30
retry_count = 2
retry_backoff_seconds = 1
[services.app.source.headers]
X-Trace = "blink"
[services.app.source.cache]
ttl_seconds = 300Current url behavior:
- caches artifacts under
.blink/artifacts/<service>/ - supports TTL-based reuse for HTTP downloads
- revalidates cached HTTP artifacts with
ETagandLast-Modifiedwhen available - blocks insecure
http://sources unlessallow_insecure = true - supports checksum and detached-signature verification
Blink currently ships these built-in steps:
fetch_artifactstopbackupinstallstarthealth_checkverifyrollbackshellremote_scriptdockerprovision
Use bin/blink steps or bin/blink steps <name> to inspect their current descriptions, supported targets, rollback behavior, and config sections.
Blink supports two verification styles:
- Ruby suite files via
verify.suite - declarative inline tests via
verify.tests.*
Both can be used together. Inline tests run first, then the Ruby suite.
Example inline checks:
[services.app.verify]
tags = ["smoke"]
[services.app.verify.tests.api-health]
type = "api"
url = "http://127.0.0.1:{{port}}/health"
[services.app.verify.tests.api-health.checks.status]
type = "status"
equals = 200
[services.app.verify.tests.api-health.checks.status_json]
type = "json"
path = "$.status"
equals = "ok"
[services.app.verify.tests.ui-home]
type = "ui"
url = "http://127.0.0.1:{{port}}/"
[services.app.verify.tests.ui-home.checks.root]
type = "selector"
engine = "css"
selector = "#app"
[services.app.verify.tests.ui-home.checks.ready]
type = "text"
contains = "Ready"Supported inline test types:
api/httpuishellmcpscript
Supported inline check types:
statusbodyheaderjsonselectortext
Notes:
- UI selector checks use Nokogiri when available.
scripttests run locally.shelland HTTP-based checks run against the selected target.
blink plan resolves and reports:
- target selection
- ordered pipeline steps
- rollback pipeline
- source security posture
- warnings
- blockers
- deterministic config hash
Blink persists run data under .blink/:
.blink/state/current.json.blink/state/recent_runs.json.blink/history/<run_id>.json.blink/artifacts/<service>/....blink/reports/latest.html.blink/reports/latest.json
Persisted data includes:
- deploy, rollback, and test summaries
- per-step results
- target and runtime metadata
- artifact SHA-256, cache metadata, and verification metadata
- recent run indexing for
state,history, andreport generate
Blink includes a current tool server behind:
bin/blink --mcpIt exposes tool handlers for:
blink_list_servicesblink_planblink_deployblink_testblink_statusblink_logsblink_restartblink_psblink_stepsblink_stateblink_historyblink_rollbackblink_doctor
Current note: the codebase exposes an MCP-style JSON-RPC tool surface over stdio for local agent integration. Transport hardening and interoperability polish are still being tracked in the project plan.
The README should stay honest about what is not implemented yet in this repo.
Not shipped today:
- Docker or MCP target types
- GitLab, OCI, or Docker image source types
- user-defined step or source plugins
- load testing
- parallel verifier execution
- drift detection or diff commands
Operational notes for the current implementation:
status,doctor, andpsare target-centric commands. In multi-target manifests, pass--targetexplicitly when you want to inspect a specific target.blink initscaffolds examples for deploy, health-check, and inline API/UI verification, but you still need to replace the build and runtime commands with real ones.- If you want authenticated GitHub API requests, set
GITHUB_TOKENorGH_TOKEN.
Run the test suite directly with Ruby:
ruby -Itest -Ilib -e 'Dir["test/**/*_test.rb"].sort.each { |f| require File.expand_path(f) }'If you use Bundler, make sure development gems are installed first.