ADB-like debugging, testing, deployment, evidence, and profiling for embedded devices.
embedctl gives embedded-device projects one local control plane for target profiles, policy-gated shell access, plan/apply file transfer and deploys, runtime logs, bug reports, evidence artifacts, performance artifacts, release checks, and OpenCode/MCP agent workflows. It is centered on embedded Linux appliance targets first. Flutter/flutter-pi support is an implemented runtime profile, not the shape every downstream project must fit.
embedctl is built around three public, reusable surfaces:
| Surface | What it gives you | Safety stance |
|---|---|---|
embedctl |
Local CLI for devices, deploy plans, logs, evidence, profiling, and release checks | Plan/apply boundaries, typed JSON, fail-closed evidence |
embedctl-mcp |
Thin MCP wrapper over the same CLI JSON surface | No separate mutation logic, same policy gates |
| Target profiles | Reusable declarations for runtime, transport, capabilities, and agent policy | Private access details stay outside public examples |
Why teams use it:
- declare target capabilities once in public-safe or private target profiles,
- preview mutations as hash-verified plans before applying them,
- collect local evidence artifacts that can feed human review, agents, and release gates,
- let MCP-capable coding agents use the same CLI JSON contract as humans.
git clone https://github.com/dongguri-jun/embedctl.git
cd embedctl
bash scripts/install-local.sh
embedctl --versionFrom a checkout, the installer builds from source when Dart is installed and otherwise falls back to matching GitHub Release binaries. Release binary assets are attached by releases created after this installer change.
It writes two user-facing commands by default:
$HOME/.local/bin/embedctl
$HOME/.local/bin/embedctl-mcp
Latest stable release: v0.2.3. The repository may be on the next -dev version after a release.
embedctl profile validate examples/profiles/flutter-pi-panel.json --json
embedctl devices --json --profiles-dir examples/profiles
embedctl capabilities --target flutter-pi-panel-example --json --profiles-dir examples/profilesThe examples are intentionally non-mutating and public-safe. They validate the command surface without requiring a real target.
Most MCP clients can run the local stdio server directly:
{
"mcpServers": {
"embedctl": {
"command": "embedctl-mcp"
}
}
}For OpenCode project config, use the local MCP shape:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"embedctl": {
"type": "local",
"command": ["embedctl-mcp"],
"enabled": true,
"timeout": 30000
}
}
}Private target profiles, adapter directories, workflow files, payload registries, screenshots, logs, bugreports, and real device access details should stay in downstream repositories or private overlays. Public examples in this repository are neutral fixtures for exercising the CLI behavior.
| Need | Command group | First command to try |
|---|---|---|
| Know what targets exist | devices, capabilities, doctor |
embedctl devices --json --profiles-dir examples/profiles |
| Preview file/deploy changes | push, pull, sync, deploy, apply |
embedctl deploy --target <id> --json --plan --bundle <bundle-path> |
| Observe runtime state | logs, screencap, visual, bugreport |
embedctl logs --target <id> --json |
| Prove release readiness | release-check, evidence inspect, evidence diff |
embedctl release-check --target <id> --json |
| Measure performance | profile steady, profile run, profile frames, profile compare |
embedctl profile steady --target <id> --output evidence/profile-steady --json |
| Let agents use it | embedctl-mcp |
embedctl-mcp |
embedctl is local-first, multi-device by design, multi-OS-ready by architecture, and AI-native by default. The core model is profile-driven Linux appliance development: declare a target, preview mutations, apply explicitly, collect logs/evidence, and keep private access details outside public examples.
The current implementation includes strong flutter-pi support because it was the first runtime profile to exercise deploy, visual, bridge, and profiling paths. That runtime is optional. Projects that only need SSH, systemd, journal, file transfer, reboot/reconnect workflows, and evidence collection should not need Flutter or Dart on the target.
The core product is the CLI and its stable JSON output. MCP servers, agent skills, and wrappers must stay thin adapters over that CLI surface rather than reimplementing deployment, profiling, evidence, or bridge semantics.
embedctl is not a general-purpose OS administration tool, not a replacement for SSH/systemd/journalctl/rsync, and not a replacement for flutter-pi or flutterpi_tool. It composes those tools behind explicit profiles, plan/apply mutation boundaries, release evidence, and hardware sizing reports.
Project-specific behavior does not belong in core. App routes, product workflows, sensitive payload formats, target hosts, target paths, screenshots, logs, bugreports, and real device access details belong in adapters, target profiles, examples, or private overlays.
- target/device registry and capability discovery
- policy-gated SSH shell, file transfer, deploy, run, restart, and log commands
- screenshots, host-side visual captures, bug reports, evidence manifests, and release checks
- app bridge planning for route/state/test flows without putting app semantics in core
- secret-safe payload handles and redaction status for sensitive workflows
- CPU, memory, thermal, pressure, launch, frame, and workload profiling artifacts
- AI-safe JSON output, typed errors, audit trails, and MCP access through
embedctl-mcp
docs/reference-adoption.mdexplains which external projects embedctl should borrow from, adapt, integrate, or avoid cloning.docs/evidence-model.mddefines the evidence bundle shape used by generated bugreport artifacts and inspection commands.docs/downstream-agent-integration.mdexplains how downstream app projects should wire embedctl into project-localAGENTS.md, private profiles, adapter manifests, and evidence workflows.docs/host-camera-capture.mdexplains host-side visual evidence capture through declared host camera sources.docs/scanner-evidence.mddefines generic scanner lifecycle, preview, decode, redaction, and resource-release evidence without product-domain payload semantics.docs/workflow-evidence.mddefines generic planned, executed, and observed workflow proof for downstream adapters without putting app-specific routes in core.docs/performance-gates.mdexplains the implemented v0.2 performance evidence path for structured target sampling, app/scanner telemetry ingestion, app-telemetry frame evidence, normalized metric schemas, and explicitrelease-check --performance-policygates, plus future backend expansion notes.docs/plan-apply.mddefines mutation safety and agent policy gates.docs/provider-interface.mddefines the read-only v0.3 provider skeleton and future adapter boundary.docs/public-safety.mddefines the public/private boundary, local-only data rules, and public repository safety checks.docs/release-management.mddefines VERSION, CHANGELOG, tag, and GitHub Release policy.docs/supported-environments.mdtracks public-safe example, tested, supported, and experimental environments plus recommended settings by runtime/profile class.docs/agent-ux.mddefines AI-agent command, snapshot, wrapper, and evidence expectations.examples/agent-guides/contains copyable downstreamAGENTS.md, adapter manifest, and target profile starter templates for project-local AI usage rules.examples/profiles/contains public-safe target profile fixtures validated by the test suite.packages/embedctl_bridge/contains an importable, default-disabled app-side bridge package for QA adapters; the CLI still treats bridge workflows as planned output until a declared live bridge backend executes them.packages/embedctl_mcp/contains the local MCP stdio adapter. It is a thin wrapper over the CLI JSON surface and should be installed asembedctl-mcpnext to theembedctlbinary.
The checkout installer compiles both native commands. Use --bin-dir or EMBEDCTL_BIN_DIR to install somewhere other than $HOME/.local/bin:
bash scripts/install-local.sh --bin-dir /tmp/embedctl-binFor source-tree development, Dart entrypoints still work, but they are not the intended downstream install surface:
dart run packages/embedctl_cli/bin/embedctl.dart --version
dart run packages/embedctl_cli/bin/embedctl.dart devices --json --profiles-dir examples/profilesStart with the installed embedctl command. Use --json for agent-safe structured output, --plan to preview mutations, and --apply --plan-file <path> when a saved plan is ready to execute.
| Area | Example |
|---|---|
| Profile validation | embedctl profile validate examples/profiles/flutter-pi-panel.json --json |
| Device discovery | embedctl devices --json --profiles-dir examples/profiles |
| Capability discovery | embedctl capabilities --target flutter-pi-panel-example --json --profiles-dir examples/profiles |
| File transfer planning | embedctl push --target <id> --json --plan --profiles-dir examples/profiles <local> <remote> |
| Deploy planning | embedctl deploy --target <id> --json --plan --bundle <bundle-path> --profiles-dir examples/profiles |
| Runtime logs | embedctl logs --target <id> --json --profiles-dir examples/profiles |
| Evidence inspection | embedctl evidence inspect evidence-bundle --json |
| Performance sampling | embedctl profile steady --target <id> --duration 60s --interval 1s --output evidence/profile-steady --json --profiles-dir examples/profiles |
| Provider skeleton | embedctl provider list --json |
| Doctor checks | embedctl doctor --target <id> --json --profiles-dir examples/profiles |
Detailed command behavior
The profile validation, device listing, and capability reporting commands are read-only. They load local JSON target profiles, return typed JSON results, and perform no target mutation. devices --json emits safe target summaries and capabilities --json reports declared capability groups plus agent policy limits. Both omit remote addresses, install paths, and launch commands.
embedctl shell --json runs through the configured target transport only when the target profile explicitly allows shell in agent_policy.allowed_commands. JSON output preserves the child command exit code, stdout, and stderr separately while keeping target remote details, install paths, and launch commands out of the response. Raw shell is intentionally policy-gated because it is powerful and should not be the primary AI-agent interface.
embedctl push, pull, and sync emit hashed plan JSON with target profile hashes in --plan --json mode. --apply --plan-file verifies the saved plan hash, current target profile hash, target policy permission for the specific command plus apply, and remote paths inside the declared install root before executing. Initial file-transfer apply is conservative: it copies files/directories through the configured file transport but refuses overwrite/delete semantics.
embedctl deploy --plan emits a hashed deploy plan with runtime mode metadata, sync/restart steps, and target profile hash. embedctl apply --plan-file verifies the saved plan hash and current target profile hash, then executes supported deploy steps through the configured transport. run and restart support --plan for preview and --apply for explicit live execution; restart never performs broad process matching when no service is declared. logs reports the configured service log source as a read-only JSON descriptor in non-follow mode, and logs --follow runs bounded, policy-gated live probes for declared service logs rather than unbounded streaming.
embedctl screencap writes a local PNG artifact when the target profile declares a screenshot backend and marks visual sensitivity as unknown. embedctl visual sources reports declared visual evidence sources, and embedctl visual capture can write local host-camera artifacts through an explicit host-side source such as host-camera; JSON output uses public-safe source labels rather than leaking local device paths. embedctl release-check evaluates release-build evidence from canonical hierarchical paths such as build/, deploy/, runtime/, release/, and bridge/, with legacy flat file names kept as fallback; missing proof becomes incomplete, while fatal logs, bridge timeouts, and unknown non-empty .err files fail closed. embedctl bugreport writes a local v0.2 evidence bundle directory with metadata, generated logs, redaction status, NDJSON transcript, verdict, and SHA-256 manifest files; --evidence-dir imports collected evidence under evidence/<relativePath> without flattening same-named files. embedctl evidence inspect validates required files, manifest hashes, transcript shape, and proof sufficiency across recursive evidence/ and logs/ content. embedctl evidence diff compares target profile hash, verdict, and artifact hashes between two local evidence bundles.
embedctl bridge snapshot returns a profile-derived app bridge snapshot without attempting a hidden connection. bridge batch validates a local flow, preserves assertions/expect blocks, and returns per-step planned status so acceptance checks stay visible without being mistaken for live app-state proof. workflow replay wraps bridge batch planning; workflow record supports seed --step recording plus a safe --live prototype that either records a profile-declared snapshot flow without payload values or returns typed unavailable JSON. profile launch, profile steady, and profile frames report measurable host Linux facts or explicit source/status/confidence/unknowns/next_actions states rather than guessing target metrics. profile run executes a bounded workload through the declared target shell and writes local artifacts, while profile compare compares compatible metrics conservatively and marks mismatches as not comparable. provider list and provider doctor expose read-only prototype adapter and hook contract records without lab access, lab leases, power control, measurement collection, or OTA mutation.
embedctl doctor --json emits read-only profile-driven checks for flutter-pi architecture, KMS/DRI graphics, render-device access, display conflicts, launch flag consistency, build/runtime artifacts, and input metadata. When the target policy allows shell, doctor enriches selected checks with read-only live probes; otherwise probe-dependent checks remain unknown rather than guessed.
See CONTRIBUTING.md for development rules, including the policy to install needed tooling immediately and keep verification scripts updated.
Run the same checks locally that CI runs on GitHub. The verifier also checks that VERSION, package versions, CLI output, and release documentation stay in sync:
bash scripts/verify.shThe verifier checks Dart formatting, static analysis, tests, CLI smoke behavior, Markdown hygiene, local links, high-signal sensitive/local-only strings, public JSON fixtures, and Git diff whitespace.
ROADMAP.mddefines the milestone-gated schedule for v0.1, v0.2, and v0.3.TASKS.mdtracks implementation and documentation backlog items before they are migrated to GitHub Issues.VERSION,CHANGELOG.md, anddocs/release-management.mdtrack release readiness before tags or GitHub Releases exist.- GitHub Issues should mirror these tasks once implementation starts, with each issue carrying phase, deliverable, verification, and safety notes.
embedctl currently ships an implemented local CLI, a default-disabled app-side bridge package, public-safe target profile fixtures, profiling/evidence commands, a thin local MCP stdio adapter, and release tracking through VERSION and CHANGELOG.md.
Mutation support is explicit only: apply, file-transfer --apply --plan-file, run --apply, restart --apply, and profile run -- <command> mutate only after a saved plan, explicit apply flag, or explicit workload command. Unsupported unsafe process matching fails closed.
Live log streaming, interactive workflow recording, real target profiling probes, and provider hardware mutation remain follow-up work.