Manage local SSH config from a workspace and host repo.
Project description
keywharf
keywharf is a Python 3.11+ CLI for selecting SSH hosts from a host repo into a local desired state, then materializing only manager-owned SSH artifacts.
It manages only:
- one explicit local state file
- one managed SSH config fragment
- one managed key directory
It does not take over the user's whole ~/.ssh/config. Only install-include may minimally append one Include block to the main SSH config.
Recommended Workflow
Create one named workspace:
keywharf init demo --directory ~
If you already have a host repo remote URL:
# edit ~/demo/config.json and set host_repo_remote_url
keywharf --workspace ~/demo repo sync
keywharf --workspace ~/demo repo host list
keywharf --workspace ~/demo repo host show demo
If you are starting from scratch:
keywharf --workspace ~/demo repo init
keywharf --workspace ~/demo repo host add demo --comment "demo host"
keywharf --workspace ~/demo repo host endpoint add demo public --hostname demo.example.com --comment "public endpoint"
keywharf --workspace ~/demo repo host auth add demo home --user fox --identity-file keys/id_demo --comment "home key"
keywharf init creates ~/demo/repo as the workspace's one host repo directory, but it starts empty. repo init writes the host repo skeleton there. repo host add creates a host shell only; endpoint and authentication options are added separately by stable name. If you want ~/demo/repo to become a real git repository, run git init, git remote add, and git push there yourself.
Then continue with normal selection and apply flow:
keywharf --workspace ~/demo select demo --endpoint public --auth home
keywharf --workspace ~/demo validate
keywharf --workspace ~/demo render
keywharf --workspace ~/demo apply
keywharf --workspace ~/demo install-include
If the manager config lives outside the default workspace root, use --config <path> instead of --workspace.
Ownership Boundary
keywharf manages:
state_pathmanaged_config_pathmanaged_keys_dir
keywharf does not manage:
- unrelated
Hostentries in the main SSH config Matchblocks- other
Includelines - user comments and ordering in the main SSH config
Workspace Discovery
Workspace resolution is explicit and predictable:
--workspaceKEYWHARF_WORKSPACE- auto-search
pwd, each ancestor, then~ - for each base directory: scan one level of child directories first, then the base directory itself
- the first directory containing
KEYWHARF_WORKSPACEwins - fail fast with the checked candidate paths listed
keywharf init <workspace_name> creates the marker, config.json, state/state.json, an empty repo/ directory, and small workspace text files from package resources. It does not touch ~/.ssh and does not initialize a git repo for you.
Formal Config And Templates
Manager config is a formal runtime config:
- defaults come from
pkg://keywharf/config_defaults/manager.json - file or mapping input is override only
- defaults and overrides are deep-merged before Pydantic v2 validation
- runtime path resolution is separate from raw config loading
Resource roles are intentionally split:
config_defaults/*.json: formal defaults for manager configtemplates/*.json: structured starter data such as the empty state filetemplates/*.j2: human-facing text templates such as workspaceREADME.md, workspace.gitignore, and the include block text
Host Repo CRUD
repo init bootstraps a local-first host repo skeleton:
- empty
config.json keys/.gitignore
It writes those files into the workspace's one host repo directory, %{WORKSPACE}/repo. It does not run git init or create .git.
repo host edits only the host repo config.json:
repo host listrepo host showrepo host addrepo host updaterepo host removerepo host endpoint listrepo host endpoint showrepo host endpoint addrepo host endpoint updaterepo host endpoint removerepo host auth listrepo host auth showrepo host auth addrepo host auth updaterepo host auth remove
These commands do not commit, push, run git init, or mutate git metadata. They perform structured JSON reads/writes, preserve array order, and revalidate the resulting host set before writing.
Design rules:
repo host addcreates a host shell and may set only the host commentrepo host endpoint ...manages named endpoint options withHostName, optionalPort, and optional commentrepo host auth ...manages named authentication options with optionalUser, optionalIdentityFile, and optional commentselectstores stable endpoint/auth names in local statevalidatescans the whole host repo and reports every host shell that is missing endpoint options, authentication options, or bothrenderandapplyonly require the hosts selected in local state to be complete
ExtraConfig is preserved and rendered, but it is not exposed as a CLI editor yet.
--sudo
Mutating commands support --sudo:
initrepo initrepo syncselectdeselectapplyinstall-includerepo host addrepo host updaterepo host removerepo host endpoint addrepo host endpoint updaterepo host endpoint removerepo host auth addrepo host auth updaterepo host auth remove
Privilege handling is centralized:
- normal writable paths run without sudo
- unwritable paths fail fast with concrete path-based reasons
--sudore-execs the full command throughsudo
Installation
python3.11 -m venv .venv
. .venv/bin/activate
python -m pip install -e '.[dev]'
pytest
Runtime requirements:
- Python 3.11+
- system
git
Documentation
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file keywharf-1.0.2.tar.gz.
File metadata
- Download URL: keywharf-1.0.2.tar.gz
- Upload date:
- Size: 56.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2383e08c2b00398b25d92ea2503ea15e2e81c071feeb2336823bdf545f388d43
|
|
| MD5 |
4f2543b54d21cf4ace703b0606f543dc
|
|
| BLAKE2b-256 |
d29f8a53096fdbce2572568aa11fa95bfbf12237745307b21d899c136755ca23
|
Provenance
The following attestation bundles were made for keywharf-1.0.2.tar.gz:
Publisher:
publish.yml on eserie-fox/keywharf
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
keywharf-1.0.2.tar.gz -
Subject digest:
2383e08c2b00398b25d92ea2503ea15e2e81c071feeb2336823bdf545f388d43 - Sigstore transparency entry: 1278555109
- Sigstore integration time:
-
Permalink:
eserie-fox/keywharf@b03b64bb1cddd12bf527082bb104727b8fd068af -
Branch / Tag:
refs/tags/v1.0.2 - Owner: https://github.com/eserie-fox
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b03b64bb1cddd12bf527082bb104727b8fd068af -
Trigger Event:
push
-
Statement type:
File details
Details for the file keywharf-1.0.2-py3-none-any.whl.
File metadata
- Download URL: keywharf-1.0.2-py3-none-any.whl
- Upload date:
- Size: 71.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e70b3a401732622bbba15d259c41c1450e4ed138838b9351ff0a9540d5889212
|
|
| MD5 |
98cb16c176ed7603e362a1e8f5ebe600
|
|
| BLAKE2b-256 |
9ce1b057fba232ded661d3316dc89c7b287940d68640ed8c265048baa94ec284
|
Provenance
The following attestation bundles were made for keywharf-1.0.2-py3-none-any.whl:
Publisher:
publish.yml on eserie-fox/keywharf
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
keywharf-1.0.2-py3-none-any.whl -
Subject digest:
e70b3a401732622bbba15d259c41c1450e4ed138838b9351ff0a9540d5889212 - Sigstore transparency entry: 1278555158
- Sigstore integration time:
-
Permalink:
eserie-fox/keywharf@b03b64bb1cddd12bf527082bb104727b8fd068af -
Branch / Tag:
refs/tags/v1.0.2 - Owner: https://github.com/eserie-fox
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b03b64bb1cddd12bf527082bb104727b8fd068af -
Trigger Event:
push
-
Statement type: