Skip to content
chucklehead-devPublic

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

a1s

Note: this codebase is AI-generated, under active development and testing, and should be used at your own peril.

a1s is a k9s-style terminal UI for AWS: browse, edit, create, and observe 1000+ resources across accounts and regions, powered by the CloudControl API.

Read-only incident triage across alarms, S3, Lambda metrics, and logs

Contents

Highlights

  • Browse any CloudControl resource across credentials, regions, and scopes — filter, sort, mark rows, pick columns (including tag:Key tag columns), and view or edit resource details as YAML.
  • Multiple credential types: SDK profiles, assumed roles (with chaining), and self-managed IAM Identity Center SSO registrations.
  • Scopes: one credential in one region, or a named group of region scopes.
  • Customizable views: persisted, per-resource type views with custom columns (including tag columns) and sorting.
  • Export resource information: Export individual or bulk resource details from your custom views to JSON(L)
  • Related-resource jump: press o on any row to see jumpable references; enter on a reference peeks that resource read-only, and peeks chain. References that use a secondary key (one that is not the target type's primary identifier) are resolved on demand by a bounded, cancellable scan of the target type before the peek opens. The reference catalog is user-extendable.
  • Write resources: + creates from a schema-derived YAML skeleton, e edits the live YAML with a diff/confirm step, bulk-delete via marked rows.
  • Type catalogue: :types opens a sorted catalogue of every known CloudFormation type — description, status, mutability, and operations — with enter to activate one.
  • Read-only mode: --readonly (or readOnly: true) disables all mutations; header shows [RO].
  • Theming: built-in skins plus user themes/ directory; per-credential accent colors as a visual guard rail for production accounts.
  • CloudWatch metrics: M opens a sparkline grid for catalogued types (Lambda, EC2, DynamoDB, RDS, SQS, SNS, …), with configurable named views.
  • Logs and history: l tails CloudWatch logs (live-follow with f); H opens CloudTrail event history with configurable time windows.
  • Scope change watch: background CloudTrail polling raises a ● N changes badge; :changes opens the scope-wide feed; stale rows are marked ·.
  • CloudWatch alarms: a ▲ N alarms badge counts alarms currently in ALARM state (all group-member regions summed); :alarms opens the alarm state-transition history feed, the companion to :changes. The badge clears itself when alarms recover.
  • Service-specific surfaces: S3 object browser, DynamoDB query-first viewer, Kinesis shard tailer, SQS poll modal, SNS publish, Step Functions executions, Secrets Manager reveal, ECS exec, Lambda invoke, SSM sessions, CloudFormation stack events, EKS → k9s handoff.

    Note: the service-specific interfaces are the most likely place you will find bugs or broken functionality..

Install

Pre-release: build from source with Go 1.26+.

go install github.com/chucklehead-dev/a1s/cmd/a1s@latest

Or build a local binary:

go build -o ./a1s ./cmd/a1s

Tagged releases will ship archives for Linux (amd64/arm64), macOS (arm64), and Windows (amd64/arm64) on GitHub Releases, plus Homebrew, Scoop, and WinGet packages.

First Run

Start the TUI:

a1s

If no credentials or scopes exist, the app opens the credentials table.

a1s uses the AWS SDK for Go and the credentials available to it: SDK profile credentials can come from the normal AWS config files, environment variables, SSO cache, instance metadata, or any other SDK-supported provider. The principal you browse with needs permissions for the AWS services and CloudControl calls used by the selected resource type; some types are region-specific, some are global, and CloudControl availability varies by type and region.

Create a credential:

  • Press s for an SDK profile credential — a picker lists the profiles discovered in your AWS config/credentials files (see SDK Profile Discovery).
  • Press a for an assume-role credential.
  • Press r for an SSO registration.
  • Mark one or more SSO registrations and press o to create SSO role credentials.

Create a scope:

  • Open the command palette with :.
  • Run scope or scopes.
  • Press r to create region scopes from one or more credentials.
  • Press g to group marked region scopes.
  • Press / inside the role and region-scope pickers to filter the list live (same substring / re: / ~ / ! grammar as the table filter).

Creating an SDK credential and region scopes

Filtering the region picker while creating scopes

Browse resources:

  • Open the command palette with :.
  • Enter a resource type such as AWS::S3::Bucket, or use an alias such as s3.
  • Move with the arrows or j/k; h/l pan wide tables horizontally.
  • Press y to open the selected resource as YAML; / inside the detail view searches the YAML (n/N jump between matches).
  • Press Y to copy the selected row's identifier to the clipboard.
  • Press / to filter the active resource table. Filters have modes: plain text is a case-insensitive substring, re: is a regex, ~ is a fuzzy subsequence match, and a leading ! inverts any of them.
  • Press digits 1–9 (and 0 for the 10th column) to sort by the addressed visible column; repeat to cycle ascending → descending → off. The sort persists per resource type.
  • Press c to choose columns, including tag:Key tag columns.
  • Press space to mark rows (ctrl+space marks a range, ctrl+\ clears marks); bulk actions like delete and tagging operate on marked rows.
  • Press shift+p to prefetch resource details.
  • Press ctrl+s to export the table to JSONL (visible columns or full properties).
  • Press ctrl+r to refresh the active screen.
  • Press E to open the grouped listing-error table when a multi-region or group browse hits per-scope failures.
  • Recall earlier palette commands and filter queries with up/down — both prompts keep a per-session history.
  • Press ? to open the fullscreen help screen (grouped by General, Resource Table, and service-specific sections).
  • Run q! from the command palette to quit.

Row marks, live filtering, the column picker, and YAML detail

Fullscreen help screen

Press o to open the selected resource's related references; enter on a jumpable row peeks the referenced resource read-only, and peeks chain.

Related references modal, secondary-key search, and read-only peek

Type catalogue

Run :types from the command palette to open the type catalogue: a sorted table of every known CloudFormation type with Type, Description, Status, Mutability, and Ops columns. The Ops column is a fixed LRCUD encoding — List, Read, Create, Update, Delete — with - for an operation the type does not support (a read-only type reads LR---, an immutable type LRC-D). When a scope is active, types that are not enabled anywhere in it render faint. Press / to filter the catalogue, and enter to activate the selected type: with a scope active it opens that scope's resource list on the type; with no scope active it drops into the scope picker so you can choose one first.

Conventions

The same verbs work everywhere they make sense:

Key Verb Where
enter Drill into the type's primary surface S3 objects, DynamoDB viewer, Kinesis shards, SFN executions, Secrets reveal, CFN stack events, EKS → k9s
+ Create / produce / publish Resource create, Kinesis record, SQS message, SNS publish, SFN execution, S3 object, DynamoDB item
ctrl+s Save / export to a file Table export (JSONL), S3 object download, SQS message body, Kinesis record body, DynamoDB item JSON
U Produce / upload from a file S3 upload, SQS message, Kinesis record, DynamoDB item
/ Filter the current table or picker Resource table, type catalogue, S3 browser, pickers, YAML search
[ / ] Widen / narrow the time range Logs, CloudTrail, metrics
esc Back / close one level Everywhere

All mutating verbs are blocked in read-only mode. Most hotkeys are rebindable via a keybindings: section in config.yaml — see docs/CONFIGURATION.md.

Views

Per-type table layout lives in a k9s-style views: section of config.yaml: an ordered columns list (property names, AccountID/Region origin columns, or tag:Key entries) plus a persisted sortColumn: Name:asc. Column-picker and digit-sort changes write back to the active type's view.

Press T over marked rows to bulk-set or remove a tag, then use c → t in the column picker to add a tag:Key column that shows the tag values inline.

Bulk tag edit and the tag:Team column

Writing Resources

+ opens a schema-derived YAML skeleton in $EDITOR; fill in the required fields, save, and confirm to send the create through CloudControl. Status polls until the operation reaches SUCCESS and the new row appears in the list.

Creating a resource from a schema skeleton

e opens the selected resource's live YAML in $EDITOR. After saving, a1s shows a diff and asks for confirmation before patching via CloudControl. Press esc to cancel without writing.

Editing a resource and cancelling the diff

Repairing a Lambda execution policy and invoking the processor

Observability

Logs and CloudTrail

Press l on a log-capable resource to tail its CloudWatch logs — f follows live; press H on any resource for its CloudTrail event history. [/] widen and narrow the time window.

A resource is log-capable either by convention — the group is derived from the row's identifier: log groups, Lambda functions (/aws/lambda/<name>), CodeBuild projects (/aws/codebuild/<name>), EKS clusters (/aws/eks/<name>/cluster), AppSync APIs — or by configuration: any resource whose loaded detail carries a log-group reference (Step Functions logging, ECS task awslogs-group, API Gateway access logs, custom Lambda/ CodeBuild groups). The configured path resolves once the row's detail is loaded.

On the CloudTrail tables (H and :changes), c opens a column picker for the event columns, just like the resource table.

CloudWatch Logs and CloudTrail history panes

CloudTrail history column picker

Change watch

While a scope is active, a1s watches its CloudTrail event history in the background and raises a ● N changes badge when something in the scope changes; run :changes to open the scope-wide change feed. Rows that were touched by a recent change event are marked with a · staleness dot in the table until they are refreshed.

CloudWatch alarms

While a scope is active, the same background watch polls each member region for alarms currently in ALARM state and renders a ▲ N alarms badge beside the ● N changes badge. The count is the live sum across all member regions; it clears itself automatically when alarms recover — it is not an unread-items counter and is not reset by opening :alarms.

Run :alarms to open the alarm state-transition history feed: every member region's DescribeAlarmHistory StateUpdate items merged into the shared event-stream pane (Timestamp | Alarm | Summary columns), windowed and navigable with [/] like the other history feeds. The peek shows the raw HistoryData JSON for each transition. Requires an active scope.

CloudWatch Metrics

Press M on any row whose resource type has catalogued metrics to open a 2×2 sparkline grid for that resource. The grid shows up to four preset metrics (Invocations/Errors/Duration/Throttles for Lambda, CPU/network for EC2, and so on) loaded in one batched call. Use [ to widen the time window (1h → 3h → 24h → 7d), ] to narrow it, and r to refresh. Press esc to close.

Press tab to cycle between a type's metric views when more than one is configured. The preset catalog can be extended in config.yaml: a metrics.views section adds named per-type views, and metrics.custom declares free-standing CloudWatch views (literal dimensions, not tied to a row) that open with :metrics <name> from the command palette — bare :metrics lists the configured names. See docs/CONFIGURATION.md.

2×2 metrics sparklines for a Lambda function

Opening a named custom CloudWatch metrics view

Service-Specific Features

S3

Press enter on an AWS::S3::Bucket row to open the S3 object browser for that bucket. The browser is prefix-aware: CommonPrefixes render as folder rows (pinned above object rows), and enter on a folder drills into that prefix. Press esc to pop back one level; at the root it closes the browser.

Key Action
enter Drill into a prefix folder
y Object metadata detail (HeadObject)
o Open object for viewing — text verbatim, JSON pretty-printed, binary as hex
Y Copy a presigned GET URL to the clipboard
/ Filter objects and prefixes in the current listing
ctrl+s Export the selected object to a local path
+ New object via $EDITOR then a key prompt
U Upload a local file (multipart for large files)
ctrl+d Delete marked objects (batch, y/n confirm)
esc Pop prefix / close browser

The breadcrumb s3://bucket › folder › subfolder › reflects the current prefix stack.

S3 object browser: prefix drill, open JSON, presign URL

Verifying a processed S3 object after a Lambda repair

DynamoDB

Press enter on an AWS::DynamoDB::Table row to open the query-first viewer. DescribeTable resolves the key schema (PK, SK, GSIs) before the form opens; the schema is cached so switching back skips the round-trip.

The query form shows: PK value (required), optional SK condition (=, begins_with, between, <, >), and an index selector (base table or any GSI by name). Submitting runs a Query; results render in a table with PK and SK pinned as the first columns.

Scan is the explicit fallback: shift+s shows a cost warning. Confirming runs a Scan with a 1-page cap; m loads the next page.

Key Phase Action
enter Resource list Open viewer
tab Query form Cycle field focus
enter Query form Run query
shift+s Viewer Scan (cost-gated); m loads the next page
y Results Item JSON detail
e Results Edit item in $EDITOR → diff → PutItem
+ Results Create item via $EDITOR
ctrl+s Results Save selected item JSON to a file
U Results Create item from a file
esc Results / detail Back to query form / results

DynamoDB query form, item detail, save, create-from-file review, and scan warning

Kinesis

Press enter on an AWS::Kinesis::Stream row to open the shard table. The table lists open shards; mark shards with space (or leave all unmarked to tail the cursor shard), choose an iterator type, then press enter to start tailing.

Iterator types: L sets LATEST (default — only new records); t sets TRIM_HORIZON (all seeded records from the beginning).

Key Context Action
enter Resource list Open shard table
space Shard table Toggle shard mark
L Shard table Set iterator to LATEST
t Shard table Set iterator to TRIM_HORIZON
enter Shard table Start tail on marked (or cursor) shard(s)
d Stream pane Decode record body (JSON pretty-print or plaintext)
f Stream pane Toggle live follow (poll-based, 2s–30s backoff)
+ Stream pane Produce a record via $EDITOR + partition key prompt
ctrl+s Stream pane Save record body to a file
U Stream pane Produce a record from a file
esc Any Back / close

Kinesis shard table, TRIM_HORIZON tail, and record decode

SQS

Press p on an AWS::SQS::Queue row to open the poll modal. Fill in the bounded poll form (number of messages, wait seconds, visibility timeout) and submit to receive messages.

Important: SQS has no side-effect-free peek. Every ReceiveMessage call increments ApproximateReceiveCount on each returned message, even in peek mode. When receiveCount exceeds the queue's maxReceiveCount, the message is automatically moved to the DLQ — without any explicit consume action. The modal warns of this prominently in the results header.

Key Context Action
p Resource list Open poll modal
enter Poll form Submit poll
x Results Consume (delete) selected message — confirm-gated
+ Results Produce a message via $EDITOR
ctrl+s Results Save message body to a file
U Results Send a message from a file
r Results Redrive DLQ messages to source (StartMessageMoveTask)
esc Any Close modal

Polling is allowed in read-only mode; consume (x), produce (+), and redrive (r) are blocked.

SQS poll form, results, and receiveCount warning

SQS message save and produce-from-file flow

SNS

Press + on an AWS::SNS::Topic row to publish. a1s opens a parameter form (subject; FIFO topics also require a message group ID), then $EDITOR for the message body, then a confirm step that shows the topic's subscriber count before sending.

Key Context Action
+ Resource list Publish to topic (form → $EDITOR body → confirm)

Step Functions

Press enter on an AWS::StepFunctions::StateMachine row to open its executions in the event-stream pane; press + to start a new execution (input JSON via $EDITOR).

Key Context Action
enter Resource list Open executions stream
+ Executions pane Start execution via $EDITOR

Secrets Manager

Press enter on an AWS::SecretsManager::Secret row to reveal its value behind a confirm gate. Revealed values are never logged, cached, or written to disk.

Key Context Action
enter Resource list Reveal secret value (confirm-gated)

ECS

Press x on an AWS::ECS::Service row to exec into a running container (confirm-gated; hands off to the session-manager plugin like SSM sessions).

Key Context Action
x Resource list Exec into a container (confirm-gated)

Lambda Invoke

Press i on an AWS::Lambda::Function row to invoke the function. a1s opens the payload in $EDITOR as a JSON file (defaulting to {}); save and quit to advance to the confirmation modal, which shows the function name, payload size, and invocation type (RequestResponse or Event, toggled with t). Press y to invoke. The result view shows the HTTP status, any function error, the response payload, and the CloudWatch log tail. Press l from the result view to jump directly to the function's CloudWatch logs.

Lambda payload editor, confirmation, and result view

EC2 / SSM Sessions

Press ! on an AWS::EC2::Instance row to start an SSM Session Manager session for that instance. a1s verifies that the instance is SSM-managed, then lets you choose between an interactive shell or a port-forwarding session. A port-forwarding session prompts for local and remote ports. Press y on the confirmation modal to start the session; a1s calls ssm:StartSession and hands the terminal over to the session-manager-plugin binary for the duration of the session.

SSM sessions require the session-manager-plugin binary on PATH. Install it from the AWS documentation. SSM sessions are blocked in read-only mode.

CloudFormation

Press enter on an AWS::CloudFormation::Stack row to open the stack's event history in the event-stream pane. The pane shows each stack event as a row (Timestamp | Logical ID | Status); the peek detail carries the full event including the status reason, which is too long to fit in a table cell but is what operators look for when diagnosing a failed deployment. Window keys ([/]) widen and narrow the time range; r refreshes.

Key Context Action
enter Resource list Open stack event history
[ / ] Event pane Widen / narrow time window
r Event pane Refresh
enter Event pane Peek event detail (status reason)
esc Event pane Close

CloudFormation stack event history and status-reason peek

EKS

Press enter on an AWS::EKS::Cluster row to hand the terminal to k9s. Before any AWS call fires, a confirmation modal names the cluster, scope, and role. Confirming calls eks:DescribeCluster through the row's origin-scope client, writes an ephemeral kubeconfig to a 0600 temp file (never ~/.kube/config), and launches k9s with KUBECONFIG pointing at it. The kubeconfig uses an exec credential plugin (aws eks get-token) so tokens are minted on demand for the whole k9s session. The temp file is deleted on every k9s exit.

Prerequisites: k9s and aws CLI must be on PATH. If either is missing a1s shows an install hint and does not open the modal.

Read-only mode: the action is read-only-gated. In read-only mode enter falls through silently to the standard open-detail behavior rather than showing a blocked-action notice, because enter has a non-mutating meaning on any row.

Key Context Action
enter Resource list Open k9s confirm modal
y / enter Confirm modal Describe cluster + write kubeconfig + launch k9s
n / esc Confirm modal Cancel
esc Preparing Cancel kubeconfig build

EKS k9s handoff confirmation, kubeconfig handoff, and TUI resume

Read-Only Mode

Start with a1s --readonly (or set readOnly: true in config.yaml) to disable resource create, edit, and delete for the session. The header shows an [RO] marker; --readonly=false lifts a read-only config for one run.

Read-only incident triage with the RO scope marker visible

Theming

skin: <name> in config.yaml selects a color skin, k9s-style: built-ins plus user skins from a themes/ directory next to the config file. A theme: block overrides individual roles on top of the skin. Credentials and scopes accept an accent: color used while that scope is active — a visual guard rail for production accounts. :accent <color> sets the active scope's accent live from the command palette (:accent none clears it), persisting to the same config field.

Live skin switch via the command palette

Resource Type Aliases

New configs include common aliases for resource types such as S3 buckets, EC2 instances, EBS volumes and snapshots, RDS instances, IAM roles and policies, Lambda functions, SQS queues, SNS topics, and VPC resources.

Use the command palette to add an alias:

alias buckets AWS::S3::Bucket

Run aliases from the command palette to open the alias table: + adds an alias, enter edits the selected one, and ctrl+d deletes it (with confirmation). Aliases are also stored in config.yaml under resourceTypeAliases, where they can be edited directly.

Resource type alias table add, edit, and delete

SDK Profile Discovery

Press s on the credentials table to open the SDK profile picker. The AWS SDK for Go has no ListProfiles API, so a1s discovers profiles by scanning the section headers of the shared config file ([default], [profile NAME] — [sso-session ...] and [services ...] sections are excluded) and the shared credentials file ([NAME]), merged config-file order first and deduplicated. AWS_CONFIG_FILE and AWS_SHARED_CREDENTIALS_FILE override the default ~/.aws/config / ~/.aws/credentials paths. Each profile is enriched best-effort with its credential-source type (sso / assume-role / web-identity / process / static) and region; a profile that fails to load still appears with blank columns.

Selecting rows creates sdkProfile credentials with the profile name as the default alias (suffixed for uniqueness). Profiles that already back a credential show as exists and cannot be re-created. If discovery finds nothing — or the profile you want is not in the files — press m for the original manual two-field form; esc there returns to the picker.

Key Context Action
s Credentials table Open the profile picker (starts discovery)
enter Picker Create credentials for marked rows (or the cursor row)
space / ctrl+space / ctrl+\ Picker Mark / range-mark / clear marks
/ Picker Filter rows live (same grammar as the table filter)
m Picker Manual entry (the original alias + profile form)
esc Picker Cancel back to the credentials table
esc Manual form Return to the picker

SDK profile picker discovery and batch credential creation

SSO Credentials

In addition to typical SDK-managed credentials, A1s can also make IAM Identity Center SSO registrations directly. SSO registrations are treated as a type of credential. Creating one opens a registration modal and starts OIDC client registration and device authorization. The modal shows the client ID, registration expiration, authorization status, and authorization expiration.

The first SSO flow that writes sensitive material prompts for a passphrase. That passphrase encrypts SSO client secrets and refresh tokens with age before they are written to credentials.yaml. If encrypted credentials already exist, startup prompts for the passphrase before launching the TUI.

SSO device authorization and role credential creation

Configuration

Configuration is split by sensitivity:

  • config.yaml stores non-sensitive settings, credentials definitions, scopes, aliases, views (columns and sort), fetch settings, keybindings, read-only mode, and skin/theme values.
  • credentials.yaml stores sensitive SSO registration material and is encrypted when it contains non-empty credentials.

By default these files live under the platform user config directory in an a1s subdirectory. On Linux this is usually ~/.config/a1s.

Caches live under the platform user cache directory in an a1s subdirectory. On Linux this is usually ~/.cache/a1s.

Useful flags:

a1s --config-dir ./config --cache-dir ./cache
a1s --reset-config
a1s --version

--reset-config clears the resolved config, credentials, and cache locations, then writes current minimal defaults without launching the TUI.

See docs/CONFIGURATION.md for the full config, keybinding, theme, and cache reference.

Development

go build -o ./a1s ./cmd/a1s
go test ./...

See docs/DEVELOPMENT.md for the full maintainer workflow and docs/ARCHITECTURE.md for design notes.

License

a1s is licensed under the Apache License 2.0. See LICENSE.

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages