kinctx is a terminal-first command library for the snippets you keep rewriting, re-Googling, or forgetting.
It lets you store commands in a local SQLite database, search them with fzf, fill in placeholder values when needed, and execute the final command directly from your terminal.
kin init
kin add
kin list
kin search
kin rm
kin helpInitializes the local SQLite database used to store your commands.
Run this once before adding, listing, searching, or deleting snippets:
kin initAdds a command to your kin store.
You can add commands in two ways:
echo 'docker logs -f ${CONTAINER:=api}' | kin addecho 'sudo systemctl restart NetworkManager' | kin addkin addWhen no stdin is piped in, kinctx opens your $EDITOR. If $EDITOR is not set, it falls back to nano.
This is the best option for:
- multi-line commands
- long commands with many flags
- commands with placeholders
Example multi-line snippet:
kubectl rollout restart deployment/${DEPLOYMENT:=api-server} \
-n ${NAMESPACE:=default} && \
kubectl rollout status deployment/${DEPLOYMENT:=api-server} -n ${NAMESPACE:=default}Lists all saved commands in a styled table, along with usage count and creation date.
kin listOpens an interactive fzf picker so you can find a saved command, fill placeholders, and run it.
kin searchWorkflow:
fzfshows your saved commands.- You select one.
kinctxdetects placeholders like${BRANCH:=main}.- It prompts you for values.
- It substitutes the values and executes the final command.
kinctx is smart enough to detect if your command doesn't have any placeholder synatx and runs it directly.
Deletes one or more saved commands using a multi-select fzf screen.
kin rmUse Tab to mark multiple entries, then press Enter to delete them.
A static command has no placeholders:
echo 'ss -tuln' | kin add
kin searchSelecting it executes ss -tuln immediately.
A dynamic command includes placeholders:
echo 'git checkout ${BRANCH:=main}' | kin add
kin searchWhen selected, kinctx prompts for BRANCH. If you accept the default, it runs:
git checkout mainkinctx uses a placeholder format inspired by shell parameter expansion:
${NAME}
${NAME:=default}Supported placeholder keys must look like:
[a-zA-Z_][a-zA-Z0-9_]*
Prompt the user for a value with no default.
Example:
echo 'ssh ${HOST}' | kin addWhen you run it through kin search, you will be asked for HOST.
Prompt the user for a value, but prefill a default.
Example:
echo 'git checkout ${BRANCH:=main}' | kin addIf you press enter without changing it, main is used.
In a normal shell, parameter expansion is handled by the shell itself. In kinctx, the syntax is used as a templating format before execution.
That means:
kinctxdetects placeholders in the saved text- it asks you for values interactively
- it replaces the placeholders with the values you entered
- it then executes the finished command
Important difference:
kinctx is not implementing full shell expansion. It supports the placeholder pattern above, not the full shell parameter expansion language.
These are not currently part of kinctx placeholder parsing:
${VAR:-default}
${VAR:+alt}
${VAR?message}
${#VAR}
${VAR%suffix}
${VAR/pattern/repl}If you want shell logic like that, wrap the command in a shell explicitly:
echo 'bash -lc '\''echo ${VAR:-fallback}'\''' | kin add- Go
fzf
go build -o kin .Then run:
./kin initRun:
kin initThis is the most important setup step. kinctx init creates the SQLite table used by the app. If you skip it, commands like add, list, search, or rm can fail because the database file may exist but the snippets table has not been created yet.
search and rm depend on fzf.
Check:
fzf --versionIf it is not installed, install fzf and try again.
That is expected. kinctx rejects blank or whitespace-only input.
Check for:
- an unclosed
${ - an empty key like
${} - malformed text like
${:=}
Valid examples:
${HOST}
${BRANCH:=main}
${NAMESPACE:=default}The store keeps commands unique. If you try to add the exact same command twice, kinctx rejects it.
kinctx stores its SQLite database under your user config directory:
$XDG_CONFIG_HOME/kinctx/sqlite-database.db
On systems without XDG_CONFIG_HOME, this resolves through Go's user config directory behavior for your platform.
MIT. See LICENSE.
