Skip to content

feat(cli): add Console API transport and positional-primary commands - #11

Merged
troian merged 65 commits into
mainfrom
chalabi/phase1-console-batch
Jul 28, 2026
Merged

troian merged 65 commits into
mainfrom
chalabi/phase1-console-batch

Conversation

@troian

@troian troian commented Jul 23, 2026

Copy link
Copy Markdown
Member

No description provided.

chalabi2 added 30 commits July 21, 2026 15:33
Committed code in internal/mcp and internal/tui already imports
github.com/mark3labs/mcp-go and github.com/charmbracelet/x/ansi, and
requires pkg.akt.dev/go v0.2.9, but go.mod/go.sum were never updated to
match. This makes HEAD build cleanly again.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
The action logger is opened in the root PersistentPreRunE but was never
closed, diverging from SPEC §5.6 which requires it to be closed in
PersistentPostRunE.

Refs AKT-211

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Write type=context action log entries for create, use, edit, delete,
and rename per SPEC §5.6. Entries go to the affected context's own log,
opened directly, because context commands often run without an open
logger for the target context (create, or switching away from the
current one). Delete records into the current context's log since the
deleted context's log is removed together with the context.

Refs AKT-211

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Wrap the chain client discovered in TxPersistentPreRunE with a logging
decorator so every tx command records a type=tx entry per SPEC §5.6 —
one choke point instead of ~40 per-command call sites. Entries carry
the compact message type, tx hash, height, gas, result code, signer,
and dseq/gseq/oseq/provider for well-known Akash messages. Failed
broadcasts record status=failed with the error; generate-only,
simulate, and offline runs are not logged since nothing is broadcast.

Refs AKT-211

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Write type=provider entries for the state-changing provider commands
(send-manifest, migrate-hostnames, migrate-endpoints, lease-shell) with
operation, provider address, dseq, and success/failure status. Read-only
provider queries stay unlogged, consistent with the action log's
mutating-actions scope; SPEC §5.6 updated to match.

Refs AKT-211

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
The workflow engine already calls Logger.LogStep after each step, but
no implementation existed. ActionLogAdapter writes one type=workflow
entry per completed step (workflow name, run ID, step index/name,
status, error, tx hash/height) per SPEC §5.6. It is nil-safe so wiring
is unconditional; workflow execution wiring uses it when constructing
the engine.

Refs AKT-211

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Add a console action type to the action log schema (SPEC §5.2/§5.6)
and record state-changing Console API calls — create/update/close
deployment, create lease, deposit — with operation, dseq, and
success/failure status. The logger attaches via an optional
WithActionLog hook so the client stays usable without one. Read-only
Console queries are not recorded, matching the action log's
mutating-actions scope.

Refs AKT-211

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
readLogFile capped scanner lines at 1 MB, so an entry with large
params that Log accepted could never be read back (token too long).
Raise the limit to the 10 MB rotation threshold and add a rotation
test covering the size-based shift to .1 and newest-first reads that
span rotated files — coverage TASKS.md T008 claimed but did not have.

Refs AKT-211

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Align SPEC §5.6 with the action log's mutating-actions scope from
AKT-211: read-only queries are not recorded by default, and
verbose-mode query logging is marked as planned rather than current
behavior.

Refs AKT-211

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
The workflow command surface is generated dynamically — a top-level
command exists iff its workflow YAML resolves (built-ins always do,
per SPEC §2.3.9) — but nothing pinned that behavior. Add unit tests
for the built-in-only surface, user workflows appearing and being
absent, malformed YAML being skipped, generated Use/flags, and
user-workflow override of a built-in. SPEC §2.3.1 now states the
dynamic surfacing rule explicitly.

Refs AKT-651

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
SPEC §7.1 previously forbade persisting the Console API key anywhere.
AKT-646 makes the key a per-context credential so switching context
switches Console identity. Resolution order becomes flag > env >
per-context credential file at contexts/<name>/console-api-key
(0600, never in config.yaml, never printed or logged; renames move it
and deletes remove it). SPEC §1.4 and DESIGN §3.1.4 updated to match.

Refs AKT-646

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
…tial

Contexts gain auth-method (keyring | console-api, validated on create)
and console-api-url fields, both round-tripping through config.yaml.
The Console API key itself is a credential, not config: it is stored
at contexts/<name>/console-api-key with 0600 permissions, moves with
renames, and is removed with the context. Resolve populates the
effective auth method, Console URL default, and the key using the
SPEC §7.1 order (env var over stored credential; flag override is
applied by the CLI layer).

Refs AKT-646

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
context create/edit gain --auth-method, --console-api-url, and
--console-api-key; the key is stored via the per-context credential
store, an empty string on edit removes it, and the action log records
only updated/removed — never the value. context show now displays the
auth method and, for console-api contexts, the Console URL plus
whether a key is configured; the key itself is never printed.

Refs AKT-646

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
A bare state keyword as the sole filter argument now selects a state
filter: akt query deployment active, akt q market lease active, etc.
Vocabularies come from the on-chain state enums rather than hardcoded
lists (which also surfaced two stale flag help strings claiming a
"matched" bid state that does not exist in v1beta5). Keywords do not
combine with identity paths, and a positional state wins over --state
since arg filters apply after flags. SPEC §3.8.2/§3.8.6 updated.

Refs AKT-650

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
tx deployment close/update and group close/pause/start, plus provider
lease-status/lease-logs/lease-events/get-manifest, accept the
deployment sequence as an optional positional argument; --dseq stays
as an override and the positional wins when both are given.
lease-shell keeps flags only because its positionals are the remote
command. SPEC §2.1 command tree and §2.4 headings updated.

Refs AKT-650

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
…rface

The client sent flat request bodies but the Console API wraps writes
and responses in a data envelope, and deposit-deployment takes
{data:{dseq,deposit}} rather than {dseq,amount} — verified against
the console-axi reference CLI. Rework the transport (envelope helper,
data unwrapping, 429/5xx retry, sentinel errors incl. idempotent
close) and expand coverage to the full managed-console surface:
deployments with settings and deposits, bids/leases, wallet and
usage, public marketplace endpoints, API keys, and provider-scoped
JWT minting. A per-context manifest cache under
contexts/<name>/manifests/ keeps the split create -> lease flow
working without re-passing the manifest.

Refs AKT-648

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Implement the engine's ChainClient and ProviderClient interfaces so
workflow steps can actually execute: msg builders for deployment
create/update/close and market lease-create that replicate the tx
command logic (SDL groups and version hash, dseq from chain height,
auto deposit from chain min-deposit params, update group-equality
guard), query routing for market.bids/leases and
deployment.deployments shaped for wait-step until templates, and a
provider gateway adapter resolving the gateway URL from the
provider's on-chain HostURI. Step outputs emit dseq as a JSON string
so templates render it verbatim instead of in scientific notation.

Refs AKT-647

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Port the managed-Console CLI surface (reference: console-axi) as a new
akt console command group: login/logout/whoami with per-context
credential storage, deployment lifecycle (list/get/create/update/
close/deposit/settings), bid list and lease create with the
per-context manifest cache, wallet and usage billing views, public
keyless marketplace commands (provider, gpu, template), api key
management, and provider-scoped jwt minting. Positional-primary
arguments per the AKT-650 convention; deployment close is idempotent;
mutations are recorded in the action log. SPEC §2.9 documents the
tree.

Refs AKT-648

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Add a console-backed ChainClient for the workflow engine implementing
the SPEC §7.5 routing: deployment create/update/close and market
lease-create map to Console API calls (deposit must be an explicit
USD amount, manifests are cached per context at create and reused at
lease-create, already-closed closes count as success), any other
message errors with the unsupported-command guidance. Queries
delegate to a chain client when available, with a Console bid-list
fallback shaped identically to the chain response so wait steps stay
auth-agnostic.

Refs AKT-647

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Step outputs rendered via fmt map syntax could not be parsed back by
the select-bid prompt step, and create-lease referenced a nonexistent
.bid.id — the builtin deploy workflow could never execute end to end.
Add a toJson template function, emit the selected bid's identity as
discrete prompt outputs with real cheapest-price selection, give the
output step an injectable writer so JSONL mode owns stdout, and fix
deploy.yaml's step params. SPEC §2.3.9's update example drops the
unimplemented foreach step with a note.

Refs AKT-647

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Replace the workflow commands' execution stub with real engine runs.
The command resolves the active context and selects the auth
mechanism per action without user involvement: console-api contexts
route tx steps through the Console API (provider steps are skipped
with a note since Console submits manifests internally; a missing
key produces guidance to set AKT_CONSOLE_API_KEY, store a
per-context key, or switch context), keyring contexts sign and
broadcast locally (standard tx flags are merged onto workflow
commands; a missing wallet yields a clear error). Pretty mode prints
per-step results; -o jsonl emits one SPEC §2.3.8 line per step; all
steps land in the per-context action log via the engine's logger.

Refs AKT-647

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Add offline end-to-end coverage for the previously untested command
groups: full keys lifecycle on the test backend including an
export/import round-trip and deterministic --source recovery, context
edit/log/rename with action-log assertions, network edit/delete with
the referenced-network guard, console-api credential handling (0600
file, key never printed), positional-argument smoke tests, and a
table-driven help walk over 113 command paths so a failure names the
offending command.

Refs AKT-222

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
localnetRPC uses AKT_E2E_RPC when set, otherwise bootstraps a
single-validator akash node container when AKT_E2E_LOCALNET=1 and
docker is available (genesis init, add-account, gentx, collect,
start; verified end to end locally), otherwise skips. Gated tests
cover block and staking queries, bank balances, and a real
tx bank send that is then asserted to appear in akt context log
--type tx — the action log acceptance path against a live chain.

Refs AKT-222

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
The repo had no CI. Add a GitHub Actions workflow with build + unit
tests, offline e2e against the built binary, and a docker-gated
localnet e2e job kept continue-on-error until proven on GitHub
runners. Concurrency groups cancel superseded runs; GOWORK is
disabled to match the repo's standalone module layout.

Refs AKT-222

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Enumerate every Console capability against its akt equivalent per the
AKT-649 acceptance criteria: covered capabilities (deployment
lifecycle, bids/leases, wallet and billing, marketplace browse,
templates, api keys, jwt minting, per-context auth), deferred items
with explicit rationale (provider-proxy streaming for managed
contexts, sdl screen command surface, web-only payment and account
flows, managed-wallet certificates), and intentional behavioral
differences from the reference CLI.

Refs AKT-649

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
query block/blocks/block-results used the SDK GetClientQueryContext,
which ignores the active context's network and falls back to the
--node default tcp://localhost:26657. Use the package-local resolver
so the CometBFT passthrough queries hit the context endpoint like
every module query. The localnet e2e block test drops its --node
workaround and now guards the behavior.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
ClientOptionsFromFlags forwarded the gas setting only when the flag
was explicitly changed, so the default --gas auto never reached the
tx factory: no simulation ran, transactions broadcast with
gasWanted=0, and every real send failed CheckTx with out-of-gas.
Always parse and apply the gas flag (auto means simulate) and reject
invalid values instead of silently ignoring them. Verified against
the localnet with a default-gas bank send; the e2e test drops its
explicit --gas workaround.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
A CheckTx result with a non-zero code was printed as success and the
CLI exited 0, so scripts could not detect failed transactions. The
tx-client wrapper is now applied unconditionally (with or without an
action logger) and converts a non-zero result code into an error
carrying the code, codespace, tx hash, and raw log.
Generate-only, simulate, and offline runs are unaffected.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
The first-run wizard now offers optional Akash Console setup after
network and keyring selection: enter a Console API key (hidden
input, validated best-effort against /v1/user/me with an
offline-tolerant warning, stored as the initial context's
per-context credential) and optionally route that context's
deployments through Console (auth-method: console-api). Both
prompts default to no and the whole step is skipped when stdin is
not a terminal.

Refs AKT-646

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
The Console API rejects empty startDate/endDate strings with a
format=date validation error, so akt console usage failed with a 400
whenever --from/--to were omitted. Omit empty dates — the API then
applies its own defaults (endDate today, startDate 30 days prior per
its OpenAPI contract) — and validate provided dates as YYYY-MM-DD
client-side before sending anything.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
chalabi2 added 27 commits July 24, 2026 08:51
A context whose auth-method is console-api may omit the network
entirely: it operates through the Console API alone and gains chain
access only when a network is attached later. This makes the API-key-
only configuration a first-class state — previously impossible since
networks required an RPC endpoint and contexts required a network.
Resolve yields an empty network for such contexts so capability
gating can disable chain-backed commands. --network validation moves
from MarkFlagRequired to RunE.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Derive a feature set from the active context (chain RPC present ->
chain-query/chain-tx/provider; Console key present -> console) and
gate the command surface: commands whose transport is not configured
fail fast with the missing capability and its remedy instead of
erroring mid-transport. Two presentation modes ship for UX feedback
via defaults.command-gating — dim (default, [unavailable] in help)
and hide (removed from listings) — plus off. Gating applies in the
root hooks and in a wrapped help func so --help short-circuits are
covered. tx, query, provider, and monitor are annotated; console and
workflow groups follow with their in-flight refactors. SPEC §2.10.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Formalize the boundary between actions and rails: internal/transport
defines Kind (chain | console) and the Transport interface; the CLI
constructs transports, never adapters, so future actions are added
once and translated per rail. Deposits gain one syntax on both rails,
translated at the boundary: 5usd/$5 for console (clear cross-rail
error on chain), coin amounts for chain (clear error on console),
bare numbers keep their historical per-rail meaning, and auto passes
through. A regression test pins that deploy/update/close expose a
byte-identical argument surface regardless of auth-method, so the
two rails can never drift apart in UX. The SPEC §2.3/§7.4 updates
for this layer landed with the preceding commit's staging.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Close the remaining console-axi parity gap: akt console logs, events,
status (--watch), shell (exec == shell with a command), and screen.
Managed contexts reach provider gateways directly — the active lease
and provider hostUri resolve from the Console API, a scoped short-TTL
JWT is minted via /v1/create-jwt-token, and the provider client is
reused with WithAuthToken, sharing the exact streaming code paths of
akt provider lease-* instead of porting the websocket relay. Console
subgroups and workflow commands gain their capability annotations
(console, chain-tx|console), completing the SPEC §2.10 gating
coverage.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Every flag that duplicates a positional argument is commented out
behind a uniform FEEDBACK(2026-07) marker, with the original
registration line preserved verbatim so any flag can be restored in
one step if user feedback asks for it. Queries gain an optional
second positional state keyword so identity+state combinations stay
expressible (akt q deployment akash1x/12345 active), and cert list
gains [owner] [state] positionals. Infrastructure flags (gas, fees,
node, follow/tail/watch, pagination, --by, defaulted gseq/oseq,
group --owner) are untouched. SPEC flag tables are annotated
disabled-pending-feedback rather than edited destructively.

BREAKING CHANGE: the disabled flag forms now fail with unknown flag;
use the positional forms documented in each command's help.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
context show now renders a Capabilities section derived from the
configuration — chain queries, chain transactions, provider gateway,
and Console API — with the remedy inline for anything unavailable, so
the CLI tells the user what their context can and cannot do instead
of only gating commands.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Port the reference CLI's SDL authoring surface as a transport-
independent akt sdl group: scaffolds lists the built-in templates
(web, gpu, multi-service, ip-lease with byte-faithful defaults),
init generates deterministic SDL YAML to stdout for piping into
akt deploy or akt console deployment create, and validate parses
via pkg.akt.dev/go/sdl and lints for unpinned or :latest images
(error) and uakt pricing (warning — softened from the reference's
hard reject because akt serves both rails). Works with no context,
key, or RPC endpoint and carries no capability gate. SPEC §2.11.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
…ides

Six defects found by code review, each verified against the built
binary before and after:

Help detection matched a bare "help" anywhere in argv — including as a
positional value — and it gates bootstrap, the no-context guard, and
capability checks, so "tx deployment close help" skipped enforcement
and broadcast. It now matches only flag forms, stops at the --
terminator, and recognizes cobra's help command separately.

The sdl and console groups were missing from requiresContext, so
offline SDL validation and env-key console calls were refused.

Capability gating ignored per-invocation overrides (--node,
--console-api-key, a positional monitor endpoint) and enforced even
when command-gating was off; help and enforcement also disagreed on
which context was active. Overrides now grant their capability, off
disables enforcement, and both paths share Manager.ActiveContext and
one mode resolution.

The console group and workflow commands ignored --context, storing
credentials under and billing the wrong context.

UpdateContext still required a network, making the network-less
console contexts CreateContext allows impossible to edit — including
by the remedy other errors suggest.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
…ures

Four money-and-safety defects found by code review:

Retries replayed every method on 5xx, so a gateway 502 after a
completed write could duplicate a deployment or charge the managed
wallet twice. 5xx is now retried only for idempotent methods; 429 is
still retried everywhere because the request was rejected before
processing.

CloseDeployment mapped every 400 to already-closed, reporting genuine
failures as success and logging them that way. Only 404 and 400s
whose body says closed or not-found map to the sentinel now.

The console transport ignored signTx.Code, so a 200 whose managed-
wallet broadcast actually failed looked like a successful step and
the deploy workflow hung until the bid timeout with the real cause
dropped. It now errors with the code, hash, and raw log, matching the
chain transport.

Manifest paths joined an unvalidated dseq, allowing traversal on both
the CLI read path and the API-controlled write path; dseq is now
validated as a plain sequence number first.

Also: a path-shaped SDL argument that does not exist is an error
instead of being posted as raw content, and empty manifests are no
longer cached.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Three defects found by code review:

Wallet credits were divided by 1e6 as if micro-denominated, but the
/v1/wallets contract reports creditAmount at dollar scale alongside a
denom — every wallet printed $0.00. Scaling removed and the denom is
now shown.

usage reported whatever the last history element carried as the total
spend: order-dependent and, even ascending, lifetime cumulative spend
rather than the requested range. The headline total now sums the
per-day values it already prints, with the lifetime figure reported
separately as the range maximum so both are order-independent.

Console deposit arguments used bare float parsing and so rejected the
unified 5usd/$5 syntax that akt deploy accepts on the same rail; both
entry points now share transport.ParseDeposit and the exported
minimum, so cross-rail coin forms fail client-side with the canonical
message instead of reaching the API.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
The $0.50 Console minimum was duplicated across the CLI, the
workflow transport, and the transport package, so a change to the
API's limit had to be made in lockstep in three places. The value now
lives in internal/console — the leaf package every Console caller
already imports, which also avoids the import cycle a transport-owned
constant would create — and transport re-exports it for callers that
speak in rail terms.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Four defects found by code review, three of them regressions from the
positional-only sweep:

A positional state was parsed, validated, then discarded whenever the
identity resolved to a single record, so "query deployment 12345
closed" printed an active deployment — and with --state removed, that
argument is the only state filter left. The detail view is kept, but
a supplied state now asserts: a mismatch fails naming both states.

tx deployment close and update no longer had any guard once --dseq
was unregistered; a missing dseq reached the broadcast pipeline as
zero. Both fail fast in an Args hook, before a connection is opened.

sdl init reported explicit zero or out-of-range count/port/as/price/
gpu values as an internal error from the post-generation self-check;
they are bounded usage errors now.

The README claimed --state still worked, contradicting the same
change set.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
The last three findings from the code review's deferred list:

doData treated a missing data envelope as success, leaving the
caller's result zero-valued — a wrong-shaped 200 or a proxy error
page would have surfaced as, for example, a deployment with an empty
dseq. Callers expecting a payload now get an error; endpoints that
return no body still pass a nil result and succeed.

Per-context directories were created 0755 even though they hold the
Console API credential, so the 0600 key file sat in a world-readable
directory. They are 0700 now.

ParseDeposit stored the caller's untrimmed string in Raw while
parsing the trimmed value, so a padded deposit in a workflow YAML
parsed here and failed when the rail adapter re-parsed it.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
The Makefile set the cosmos-sdk version variables but never
main.version/commit/date, which is what akt version prints — every
binary reported dev/none/unknown regardless of how it was built. Both
are injected now, and --long (promised by the version task but never
implemented) prints the build date, Go version, platform, and build
tags alongside them.

Also folds the Console compatibility matrix into SPEC §7.8: docs/
holds only dated superpowers plans and specs, so a standalone
reference document there matched no existing convention. The content
is refreshed while moving — live lease operations, bid screening, and
SDL authoring have shipped since it was written.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Bring every document in line with the branch. DESIGN gains the
architecture this work introduced: Console provider-gateway access
through a scoped Console-minted JWT and why that beats reimplementing
the websocket relay, the action-to-transport translation layer with
the unified deposit syntax as its concrete cross-rail normalization,
and capability gating with the annotation semantics and presentation
modes. Its package listing now matches disk, and the naming collision
between the wire transport and the translation layer is called out.

SPEC documents akt version --long and akt completion, the only
commands in the tree lacking a reference section, and corrects a
claim that template sdl pipes into akt deploy — only sdl validate
reads stdin.

README documents capability gating with the context show capabilities
block, the sdl group, the expanded console surface including live
lease operations, the disabled TUI shell, and the positional forms
that replaced the disabled flags.

AGENTS records the conventions this branch established so they
survive it: positional-primary commands and the guard test that
enforces them, the disabled-flag marker, capability annotations for
new command groups, actions in workflows with behavior in transport,
the action log write paths, and GOWORK=off for direct go commands.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
The release path was broken in ways that would only have surfaced at
tag time. goreleaser passed {{ .Env.BUILD_LDFLAGS }} to every build,
but nothing set it: the Makefile assigned GORELEASER_LDFLAGS two
lines before ldflags itself was defined, so releases would have
shipped with empty ldflags, reporting dev/none/unknown and building
without tags. ldflags are now literal in the goreleaser config and
driven by its own version, commit, and date templates.

Darwin builds linked libwasmvm through an rpath into the builder's
module cache, so a released macOS binary would not have run on any
other machine; the static_wasm tag now links the static archive.
The pinned goreleaser-cross tag did not exist, project_name was
inherited from the node repo, and RELEASE_DOCKER_IMAGE pointed at
that repo and was declared twice.

Adds the release targets the makefile never had, including one that
fetches the libwasmvm archives every -L flag already assumed, and a
tag-triggered workflow with a manual check/snapshot/dry-run mode.

Verified locally: config check, full four-target cross-compile with
cgo, universal darwin binary, archives, deb/rpm, checksums, and the
resulting binaries executed on three platforms reporting real
versions. Publishing is unexercised — no tag was pushed.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
The repo had no lint config and measured no coverage, and CI ran
neither. Adds a curated golangci-lint config that takes the tree from
1045 findings to zero — style linters are excluded for the chain-sdk
clean copy but correctness linters stay on, and every exclusion
carries its reason. The Makefile pin had to move to v2.11.4: v2.3.0
is built with Go 1.24 and refuses to load a config targeting this
module's go 1.26.1.

Coverage now has three package sets: repo-wide reported, akt-authored,
and the risk-carrying core gated at 65% (currently 68.7%, up from
54.9% on 136 new tests covering money paths, credentials, gating,
the action log, and the transport layer). Repo-wide sits at 30.9%
because the clean-copied chain CLI is 37.6% of all statements at
3.5%, so the previously claimed >80% target was never reachable.

Two latent crashes are fixed here because lint and coverage work
surfaced them independently: rendering staking params or pool
panicked on fields a node omits (proto3 drops zero values, leaving a
nil big.Int that panics on arithmetic), and SaveConfig discarded the
close error on config.yaml, reporting success for a failed write.

The localnet job keeps a pinned node image so a red run means this
change broke something; a scheduled job runs the same suite against
:latest to catch upstream drift without reddening pull requests.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
CI triggers on push to main and pull requests. The upstream-node
drift check keeps its job but is manual-dispatch only, so it can be
run on demand before a release without a cron adding noise.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Two failures from the first CI run on this branch.

golangci-lint-action v6 rejects a v2 version string outright; v2 needs
action v7.

The coverage job was the first thing in CI to call make, which
exposed that the Makefile only works under direnv: AKT_ROOT is set by
.envrc alone, so every include resolved to an absolute /make/... path,
and the devcache paths the coverage targets write to were empty. The
Makefile now derives AKT_ROOT from its own location when the
environment does not provide it — captured immediately, since a
deferred assignment expands inside the include lines, where
MAKEFILE_LIST has already advanced to the included file. The job
reconstructs the .env-derived cache paths the same way the release
workflow does, rather than duplicating them.

Also derives the version once with a fallback: git describe fails in
a checkout without tags, which CI does not fetch, printing a fatal
and silently producing an empty -X value.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
The first tagged release died with "no space left on device" partway
through the darwin/amd64 cross-compile. The release needs roughly
10 GB — the goreleaser-cross image alone is ~7.4 GB, before the
module cache, the libwasmvm archives, and four cgo builds worth of
output — and a stock runner does not have that headroom.

Removes preinstalled toolchains this job never uses (android, dotnet,
swift, ghc, CodeQL, powershell, boost), which reclaims about 25 GB.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
The repository table named `akash-network/akt` as this repository while
also listing `ovrclk/akt` as a superseded MVP prototype. Both are the
same GitHub path: this repository's history begins with an initial
commit at `ovrclk/akt`, the rewrite having replaced the prototype in
place. `akash-network/akt` does not exist, so nothing could be cloned,
filed, or downloaded from the name the design doc gave.

Name the repository as it is, mark the prototype row as the pre-rewrite
incarnation of the same path, and keep the possible move to
`akash-network/akt` as a stated future rather than present tense.

The package tree now roots at the module path, which is what imports
actually spell and what neither GitHub name conveys. The unused release
image path follows the same org, its comment already noting that no
`dockers:` section consumes it.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
Both gating modes shipped so the choice could be made from use rather
than a guess. The choice is now made: `dim` stays the default, so an
unavailable command is still listed and still explains itself instead of
vanishing from help.

No behavior change -- ParseMode already falls through to dim for an empty
or unrecognized value, and nothing writes command-gating into config.
This only stops the docs from listing a decision that has been made as
one still outstanding. `hide` and `off` remain available.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
`akt version` on an unconfigured machine reached the first-run wizard.
In a terminal that blocks on interactive input; outside one it printed
the wizard's "no terminal is available" notice to stderr before the
version, so a clean run looked like a failure. Both are wrong for the
command people run to check that a binary works at all -- it was the
first thing the published v0.0.1-a0 binary did when smoke tested.

Bootstrap already skipped help invocations, on the reasoning that help
must work with nothing configured. The same reasoning covers any command
whose output does not depend on configuration, so gate it on a new
requiresConfig predicate. It is deliberately narrower than
requiresContext: exempt only where the output is identical with or
without configuration -- version (build metadata is compiled in),
completion (generated from the command tree), and sdl (entirely local,
so demanding a network fetch before linting a local file is backwards).
Context and monitor commands still bootstrap, where a first-run wizard
is the point rather than an obstacle.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
The localnet suite tested four things -- a block query, staking
validators, a bank balance, and a bank send -- so the modules this CLI
exists for had no live coverage at all. Deployment, market, provider,
cert, escrow, audit, bme and oracle were exercised only offline, where a
command proves it parses its arguments and nothing more. A query that
builds a malformed request or mishandles an empty result set passed
every test we had.

Add a read-only matrix across every module and a deployment lifecycle:
publish a client certificate, create a deployment from the scaffold
`akt sdl init` emits, observe the order the market opens for it, read
its group and escrow account, then close it and watch the state change.
The close path asserts through `query deployment <owner> closed`, so the
positional state filter -- a headline change of this branch -- is
finally checked against a chain rather than an argument parser.

Two facts the harness had to learn. Deployment deposits must match the
denom the SDL prices in, and the scaffolds price in uact, so genesis now
funds both denominations and the test reads the denom out of the
generated SDL instead of hardcoding one that drifts. And a client
certificate is a hard prerequisite: without one on disk, deployment
create fails before it builds a message.

Each test function boots its own node. The lifecycle mutates chain
state, so sharing one would make the query results depend on test
order. That costs about 25 seconds against a 20 minute budget.

Bid, lease, manifest send and the provider gateway commands stay
uncovered here: all of them need a provider bidding on the order, and a
single-validator node has none. On the console rail, add the read paths
that take no arguments; everything else there either mutates or needs a
live dseq.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
`query params` is the x/params command group, not a query: its only
subcommand, subspace, takes arguments. A group prints its help and exits
0 without ever reaching the chain, so it passed the matrix locally no
matter what the node did -- and in CI it took the other path and failed
outright, which is how it was caught.

Auditing the rest against a context pointed at a dead endpoint, every
other entry exits non-zero, so all 23 genuinely round-trip to a node.
That check is now written down as the bar a new entry has to clear.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
`akt console logs <dseq>` printed all 413 lines of a live deployment's
logs and then exited 1. A provider ends a non-follow stream by closing
the connection once it has sent everything rather than by sending a
close frame, which the websocket layer surfaces as "unexpected EOF";
any non-empty close reason was reported as an error. So a completely
successful fetch failed, and `akt console logs <dseq> && next` never ran
next. `akt console events` had the same handler and the same bug.

Only the non-follow case is forgiving. In follow mode the user asked for
an open-ended stream, so an EOF really did cut it short and is still
reported, as is any other close reason in either mode.

Found by running the read-only Console suite against a live account,
which is exactly the gap the suite could not cover before.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
The live Console suite only ran commands that take no arguments, so
lease status, the bid list, and the provider-gateway log fetch went
untested -- and the log fetch was where the exit-status bug was hiding.

Discover an active deployment with an active lease from the account the
key belongs to, then exercise those three read paths against it, or skip
when the account has none. The logs case asserts the exit status rather
than the output, since the bug it guards printed every line correctly
before failing.

Nothing here creates a deployment: that spends real funds. Bid, lease
and manifest send stay uncovered for the same reason.

Signed-off-by: Joseph Chalabi <chalabi.joseph@gmail.com>
@chalabi2 chalabi2 changed the title Chalabi/phase1 console batch feat(cli): add Console API transport and positional-primary commands Jul 28, 2026
@troian
troian merged commit 91a1618 into main Jul 28, 2026
6 checks passed
@troian
troian deleted the chalabi/phase1-console-batch branch July 28, 2026 16:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants