infrastructure · cli
rostr
One inventory, several standard artifacts, no new runtime dependency.
rostr keeps server knowledge in a versioned YAML inventory layer and derives SSH configuration, Ansible inventory, and a small host list from it. The tool shortens paths without replacing SSH or Ansible.
$ rostr validate
✓ Inventory is valid
$ rostr sync
✓ SSH config updated
✓ Ansible inventory updated
✓ hosts.txt updatedContext
Three copies of the same knowledge
Before rostr, server data lived in SSH configuration, Ansible inventories, and personal memory at the same time. New hosts, changed users, or a different operating state had to be reconciled in several places. Drift was rarely visible immediately.
Constraint
The shortcut must not become lock-in
The CLI could make access easier, but it could not place a proprietary runtime between the operator and the infrastructure. Inventory stays YAML, automation stays normal Ansible, and stacks stay Docker Compose. Generated files are output, not another manually maintained source.
Architecture
One readable source, deterministic derivations
During sync, rostr reads the inventory groups, applies defaults, validates fields, and writes three operational views. Tags and operating systems also become Ansible groups. Targets can be explicitly excluded from Ansible management.
- 02SSH configdirect access and jump aliases
- 03Ansible inventorygroups by area, tag, and OS
- 04hosts.txtsmall human-readable overview
Decisions
What is intentionally built this way
Standard formats remain independent
SSH, Ansible, and Compose must remain directly usable. rostr is a helper and control surface, not a required runtime layer.
Tradeoff: Some workflows stay less polished because the standard tool remains the final authority.
Generated output is never edited by hand
Changes belong in the inventory. A new sync may replace every output completely.
Tradeoff: Local exceptions must become inventory data or explicit generator logic.
An inventory target is not automatically Ansible-managed
An explicit management state keeps systems out of generated Ansible inventory when playbooks have no mandate there.
Tradeoff: That boundary must be deliberately set and reviewed when a host is recorded.
Fork instead of a complete rewrite
The useful inventory and CLI base came from the MIT-licensed upstream. The private fork extends it into a personal infrastructure control repository.
Tradeoff: Upstream provenance and private operating scope must remain separately and honestly described.
Implementation artifacts
Small excerpts that prove the behavior
group:
name: Production
code: production
servers:
- hostname: app-primary
ip: 192.0.2.10
os: ubuntu-24.04
tags: [web, docker]
ansible_managed: true
active: true# Auto-generated by rostr
Host app-primary
HostName 192.0.2.10
User deployrostr/
├─ src/rostr/ CLI
├─ inventory/ source
├─ ansible/ standalone
├─ stacks/ standalone
└─ generated/ output onlyState and lessons
Less drift, more visible boundaries
What changed
One inventory change can refresh the operational views together. The same repository context also carries independently runnable Ansible playbooks used, among other work, for the dedicated-server rebuild in June 2026.
Drift is an architecture problem.
What remains imperfect
- A single source can still become stale. Generation removes duplication, not the obligation to maintain it.
- The private fork grew from an inventory CLI into a broader control repository. That extra surface demands more discipline around ownership and tests.
- Local SSH-agent and include configuration remains necessary for some convenience paths. The generated standard files can still be inspected separately.