Architecture
How the core, the commands, the adapters and the transaction engine fit together.
Skillporter is a local-first Python 3.9+ program with no runtime dependencies. One core implements the behavior. The CLI, the uvx and npx launchers, the standalone zipapp, the GitHub Action and the MCP server are thin entry points into it.
CLI npx launcher GitHub Action MCP server (stdio)
| | | |
+--------------+--------+--------+------------------+
|
cli.py -> skillporter/commands/*
|
+-----------+-----------+-----------+-----------+-----------+
| | | | | |
sources security install manifest diagnose harnesses
resolve analyze transact lock compare adapters
Principles
- One core. All behavior lives in
skillporter/and uses the standard library only:ast,argparse,hashlib,json,pathlib,subprocess,tarfile,zipfileand others. - Commands are thin.
cli.pydefines the argument schema and dispatches to handlers inskillporter/commands/. Handlers call domain modules and format output. - Writes are crash-safe. State, manifest, lockfile and journal writes go to a temporary file in the same directory, are flushed, and are renamed into place.
- Mutations are serialized. A re-entrant cross-process workspace lock wraps anything that changes the workspace:
flockon POSIX,msvcrtlocking on Windows. - Untrusted input is never executed. Source resolution, extraction, validation and scanning read files. They do not run them.
Modules
| Module | Responsibility |
|---|---|
cli.py, commands/ |
Argument parsing, dispatch, text and JSON output, exit codes. |
sources.py |
Resolving GitHub shorthand, Git URLs, archives and local paths. Hardened extraction. |
security.py, scanner_analyzers.py |
Risk scoring, completeness tracking, Python AST, JavaScript, Markdown, encoded-payload and cross-file analyzers, SARIF export. |
install.py, atomic.py, state.py |
Transactional planner and installer, shared-directory ownership, backups, crash recovery, rollback. |
manifest.py, resolver.py |
skillporter.yaml parsing, skillporter.lock validation, reproducibility checks, dependency resolution. |
harnesses.py |
The adapter registry and the declarative adapter loader. |
diagnose.py |
Reachability, drift, duplicate detection and custom harness path selection. |
environment.py |
Unified environment snapshot reconciling manifest, lockfile, state and disk, plus diff_environments. |
portability.py |
Hybrid .skillpack archive export, SHA-256 integrity verification, secret filtering and offline restoration. |
profiles.py |
Named environment profiles under .skillporter/profiles/ and local store caching. |
formats.py, frontmatter.py |
Specification validation and adapted rule file export. |
mcp_server.py, bundled_skill/ |
The JSON-RPC stdio server and the official skillporter AI agent skill. |
audit.py |
The scrubbed .skillporter/audit.jsonl event log. |
An install, step by step
sources.pyresolves the source into a temporary directory and records the commit.frontmatter.pyvalidates eachSKILL.md.security.pyruns the static assessment. A blocking result stops here.install.pyplans destinations and deduplicates shared directories.- Content is staged under
.skillporter/tmp/txn-<id>/andjournal.jsonrecords every path that will be created or replaced. - Directories are moved into place. Replaced content is kept until the whole transaction succeeds.
state.pyrecords what is managed, andmanifest.pyupdates the lockfile whensyncorlockruns.
If any destination fails, the earlier ones are restored. If the process dies, recover_interrupted_transactions() rolls back the unfinished transaction on a later run.
Skill discovery
Discovery stops descending once it finds a SKILL.md, so a skill's own subdirectories are not mistaken for more skills. It tracks device and inode numbers to avoid symlink loops, and it skips directories such as .git and node_modules.
Adapters are data
Each harness is a declarative record: the paths it reads, their scope and precedence, capabilities, detection rules, support type, verification tier and a link to vendor documentation. The CLI matrix, the installer's destination planning and the compatibility table on the website all come from that one registry.
The website
The site in website/ is a static build that reads its harness, CLI and release data from files generated out of the Python sources. It ships nothing into the Python package. See website/README.md.
The full design notes are in ARCHITECTURE.md at the repository root.