A daemon + CLI/TUI to manage OCI context (profile, tenancy, compartment, region) akin to kubectl contexts. Designed to work with other tools by exposing context over a local socket or via oci-context export.
- Daemon (oci-contextd /
oci-context daemon serve): serves Unix socket APIs and can run background auth validation/refresh loops. - CLI/TUI (oci-context): manage contexts, switch current context, export env/JSON, control daemon, and pick via TUI selector.
One-line install (default: oci-context latest stable):
curl -sSL https://raw.githubusercontent.com/adrianmross/oci-context/main/install.sh | bashInstall daemon binary instead:
TOOL=oci-contextd curl -sSL https://raw.githubusercontent.com/adrianmross/oci-context/main/install.sh | bashInstall a specific version:
VERSION=v0.1.0 curl -sSL https://raw.githubusercontent.com/adrianmross/oci-context/main/install.sh | bash/to start filtering the current list; hotkeys are suppressed while typing.Enterapplies the filtered list and in-region modes stages the selection.Spacestages/highlights the current row (pending save); staged items show in magenta.Ctrl+Sorqsaves the staged/current selection from any mode.- Hotkey casing rule: in the main menu (
contexts) use lowercase hotkeys; in submenus (tenancies,compartments,regions) use uppercase hotkeys. - Main menu (
contexts):ropens regions,copens compartments,topens tenancies. - Submenus:
Ropens regions,Copens compartments,Topens tenancies,Preturns to profiles/contexts. - Navigation:
backspacegoes up/back. - Quit without saving:
EscorCtrl+C.
Config resolution
- Default path (global):
~/.oci-context/config.yml - Project-aware auto-detection (when
--confignot set and-g/--globalnot set): first match wins in this order./.oci-context.yml./.oci-context.json./.oci-context/config.yml./.oci-context/config.json./oci-context.yml./oci-context.json./oci-context/config.yml./oci-context/config.json
Global vs project selection
--configalways overrides-g, --globalforces the global config (~/.oci-context/config.yml)- Otherwise the first project-local file found (above) is used; if none found, fall back to global
options:
oci_config_path: ~/.oci/config
socket_path: ~/.oci-context/daemon.sock
default_profile: ""
daemon_contexts: []
contexts:
- name: dev
profile: DEFAULT
tenancy_ocid: ocid1.tenancy.oc1..aaaa
compartment_ocid: ocid1.compartment.oc1..bbbb
region: us-phoenix-1
user: alice@example.com
notes: dev tenancy
- name: prod
profile: PROD
tenancy_ocid: ocid1.tenancy.oc1..cccc
compartment_ocid: ocid1.compartment.oc1..dddd
region: us-ashburn-1
current_context: devRequests include:
{ "method": "get_current" }{ "method": "use_context", "name": "dev" }{ "method": "list" }{ "method": "add_context", "context": { ... } }{ "method": "delete_context", "name": "dev" }{ "method": "export", "format": "env|json" }{ "method": "auth_status", "name": "dev" }(name optional; defaults to current)
Responses: { "ok": true, "data": ... } or { "ok": false, "error": "..." }.
oci-context --versionoroci-context -voci-context initoci-context listoci-context currentoci-context oci -- <oci args...>(runs OCI CLI with current context defaults)oci-context use <name>oci-context addoci-context set <name> --field valueoci-context delete <name>oci-context statusoci-context export --format env|jsonoci-context auth methods|show|set|set-user|login|refresh|validate|setup|notifyoci-context setup(bootstrap config + daemon; auth optional with--with-auth)oci-context daemon serve [--auto-refresh --validate-interval 5m --refresh-interval 15m]oci-context daemon install(installer entrypoint; use subcommands for specific targets)oci-context daemon up(one-command restart + nudge after return/wake)oci-context daemon doctor(diagnose daemon/service/socket/auth health)oci-context daemon auth-status [--context <name>]oci-context daemon nudge [--context <name>]oci-context daemon monitor list|add|remove|clearoci-context daemon install launchd|sleepwatcher|hammerspoon|systemdoci-context auth notify(macOS manual trigger)oci-context tui
To run plain oci ... commands without repeatedly passing --profile, --region, and --compartment-id, load managed OCI CLI defaults once per shell:
eval "$(oci-context export -f oci-env)"This sets:
OCI_CLI_RC_FILEto a managed rc file updated from your current contextOCI_CLI_CONFIG_FILEto your configured OCI config path
After that, when you run oci-context use ... (or save from TUI), the managed OCI CLI defaults are refreshed automatically.
Prints only the current context name.
$ oci-context current
dev
Shows current context details with friendly names by default.
Default human-friendly multiline (omits profile line when context == profile):
$ oci-context status
context: dev
profile: DEFAULT
tenancy: My Tenancy (ocid1.tenancy.oc1..aaaa)
compartment: My Compartment (ocid1.compartment.oc1..bbbb)
user: Alice (ocid1.user.oc1..cccc)
region: us-phoenix-1
Plain OCIDs only (-p):
$ oci-context status -p
context=dev profile=DEFAULT tenancy=ocid1.tenancy.oc1..aaaa compartment=ocid1.compartment.oc1..bbbb user=ocid1.user.oc1..cccc region=us-phoenix-1
Single-line friendly with abbreviated OCIDs (-o plain):
$ oci-context status -o plain
context=dev profile=DEFAULT tenancy=My Tenancy (ocid1…aaaa) compartment=My Compartment (ocid1…bbbb) user=Alice (ocid1…cccc) region=us-phoenix-1
Structured outputs:
$ oci-context status -o json
{ "context": "dev", "profile": "DEFAULT", ... }
$ oci-context status -o yaml
context: dev
profile: DEFAULT
...
Errors:
- If no current context is set, returns:
no current context set. - If a bad
-ovalue is provided, returns:unsupported output format: <value>.
- Shell:
eval $(oci-context export --format env)sets OCI_CLI_PROFILE, OCI_TENANCY_OCID, OCI_COMPARTMENT_OCID, OCI_REGION. - Tools: read JSON via
oci-context export --format jsonor query the socket.
The daemon can monitor and maintain auth for one or more contexts in the background.
- If
options.daemon_contextsis empty, daemon monitorscurrent_context. - If
options.daemon_contextshas entries, daemon monitors all listed contexts. security_tokencontexts: daemon validates and refreshes based on intervals.- Other auth methods: daemon validates only.
- Failure handling uses exponential backoff and stderr rate-limiting to reduce noise.
Manage monitored contexts:
oci-context daemon monitor add dev prod
oci-context daemon monitor list
oci-context daemon monitor remove dev
oci-context daemon monitor clearTrigger immediate maintenance without waiting for interval:
oci-context daemon nudge
oci-context daemon nudge --context devRun daemon with auth maintenance enabled:
oci-context daemon serve --auto-refresh --validate-interval 5m --refresh-interval 15mCheck runtime status:
oci-context daemon auth-status --context dev
oci-context auth show --context devOne-shot install/reload (recommended):
oci-context daemon installVerbose mode for setup/doctor/up/install commands:
oci-context daemon install --verbose
oci-context daemon doctor --verbose
oci-context daemon up --verboseThis writes the launchd plist, (re)loads it, and kickstarts the job so the running daemon uses the current binary.
Quick recovery when you return to your computer:
oci-context daemon upThis kickstarts the launchd daemon and sends an immediate nudge.
Run diagnostics:
oci-context daemon doctorShort aliases:
oci-context daemon fix==oci-context daemon recover==oci-context daemon upoci-context daemon check==oci-context daemon doctor
Generate a plist:
oci-context daemon install launchd \
--binary /path/to/oci-context \
--config ~/.oci-context/config.yml \
--auto-refresh \
--validate-interval 5m \
--refresh-interval 15mThen load/start:
launchctl unload ~/Library/LaunchAgents/com.adrianmross.oci-context.daemon.plist 2>/dev/null || true
launchctl load ~/Library/LaunchAgents/com.adrianmross.oci-context.daemon.plist
launchctl start com.adrianmross.oci-context.daemonAfter reinstalling/upgrading oci-context, restart the running launchd job so the daemon picks up the new binary. Otherwise, IPC commands can hit stale behavior (for example, daemon nudge returning method not implemented while help/docs show it):
launchctl kickstart -k gui/$(id -u)/com.adrianmross.oci-context.daemonInstall wake hook automation (restarts daemon + nudges auth checks on wake):
brew install sleepwatcher
oci-context daemon install sleepwatcherInstall managed Hammerspoon integration plus a wake hook script that sends clickable notifications. Clicking Re-auth now runs oci session authenticate for the affected profile.
brew install --cask hammerspoon
oci-context daemon install hammerspoonNotes:
- This command writes/updates:
~/.hammerspoon/oci_context.lua(managed URL handler + auth task runner)~/.hammerspoon/init.lua(addspcall(require, "oci_context")when missing)~/.wakeup(wake script that nudges daemon and raises actionable notifications on auth failures)
- If you prefer manual reload, run with
--reload=falseand then:
open -g 'hammerspoon://reloadConfig'Manually trigger an actionable notification from CLI:
oci-context auth notify --context dev --reason "manual check"
oci-context auth notify --context dev --reason "manual check" --tenancy-name your-tenancy--tenancy-name is optional. When omitted, notify uses the selected context's tenancy_ocid.
--native-notify defaults to false; enable it if you also want a native macOS notification.
If terminal-notifier is installed, notify uses it and clicking the native notification opens the Hammerspoon URL action.
One-shot install for a user service:
oci-context daemon install systemdRun project/global config bootstrap and daemon setup in one command:
oci-context setupUseful options:
--no-daemonskip daemon setup--with-authalso run auth setup for selected context--context <name>choose auth setup context--verboseprint underlying system commands
or generate manually:
Example unit file (~/.config/systemd/user/oci-context-daemon.service):
[Unit]
Description=oci-context daemon
After=network-online.target
[Service]
ExecStart=/path/to/oci-context daemon serve --config %h/.oci-context/config.yml --auto-refresh --validate-interval 5m --refresh-interval 15m
Restart=always
RestartSec=5
[Install]
WantedBy=default.targetEnable and start:
systemctl --user daemon-reload
systemctl --user enable --now oci-context-daemon
systemctl --user status oci-context-daemonWork in progress.
- Go (from
go.modgo version; currently 1.25.6) actionlint(for workflow linting):brew install actionlintorgo install github.com/rhysd/actionlint/cmd/actionlint@latestact(for local workflow dry runs):brew install actorgo install github.com/nektos/act@latest
Check tool availability:
make toolsRuns formatting, vet, tests, actionlint, and an act dry run against a sample PR payload:
make validateTargets:
make fmtmake vetmake testmake lint-workflowsmake validate-workflows(uses.github/testdata/pull_request.json)
- CI (
.github/workflows/ci.yml): on push/PR to main/develop/release/**; runs gofmt (checks diff), go vet, go test, actionlint. - Release (
.github/workflows/release.yml): on tagv*or manual dispatch; validates tag, runs tests, and uses GoReleaser to publish cross-platform tarballs pluschecksums.txt. - CD (
.github/workflows/cd.yml): manualworkflow_dispatchwithenvinput; placeholder deploy step to be customized.
git tag v0.1.0
git push origin v0.1.0This triggers the Release workflow, builds binaries, and attaches them to the GitHub release.
Example dry-run of CI with act (requires Docker):
act pull_request --eventpath .github/testdata/pull_request.json --dryrunPrivate GitHub repo: https://github.com/adrianmross/oci-context