Agent-facing skill catalog, deployment, and retrieval for SilvaEngine.
- Python 3.8+
HSK_SKILL_ROOTenvironment variable pointing to your skills directory- AWS credentials if using DynamoDB backend (or PostgreSQL for PG mode)
pip install -e .import logging
from harness_engineering_engine.main import HarnessEngineeringEngine
engine = HarnessEngineeringEngine(
logger=logging.getLogger(),
db_backend="dynamodb",
region_name="us-east-1",
aws_access_key_id="...",
aws_secret_access_key="...",
hsk_skill_root="skills/",
)The engine exposes the following GraphQL operations:
| Operation | Type | Permission | Purpose |
|---|---|---|---|
ping |
Query | — | Ping the GraphQL service to confirm it is operational. |
skills |
Query | Admin | Retrieve the full catalog of registered skills (admin use only). |
searchSkills |
Query | Tenant-read | Semantic search across active skills available to an agent. |
skill(name) |
Query | Tenant-read | The primary agent read path. Resolves the active version, refreshes the local cache straight from git if stale, and returns the full SKILL.md body alongside metadata. |
cliPackages |
Query | Admin | Retrieve the full catalog of registered CLI packages. |
cliPackage |
Query | Admin | Retrieve metadata for a specific CLI package. |
insertUpdateSkill |
Mutation | Admin | Raw database-level skill registration (superseded by deploySkillPackage). |
deleteSkill |
Mutation | Admin | Delete a skill registration from the system. |
deploySkillPackage |
Mutation | Admin | Core deployment path. Clones the given git remote at gitRef, resolves the commit SHA, registers the skill, and automatically activates the first-ever version. |
refreshLocalSkills |
Mutation | Admin | Force a local refresh from the database for all skills. |
rollbackSkill |
Mutation | Admin | Revert the active status of a skill to a previous version. |
promoteSkillVersion |
Mutation | Admin | Promote a specific inactive version of a skill to be the active execution version. |
disableSkill |
Mutation | Admin | Disable a skill globally for the tenant. |
pruneSkillVersions |
Mutation | Admin | Clean up old cached versions from the local file system. |
registerSkills |
Mutation | Admin | Scan a local HSK_SKILL_ROOT and bulk register all discovered skills. |
runCommand |
Mutation | Tenant-execute | Execute a local subprocess for a skill. Checked against the allowed_commands frontmatter array for security, with built-in caps on execution time and output size. |
insertUpdateCliPackage |
Mutation | Admin | Register or update a CLI dependency package mapped to a GitHub repository. |
deleteCliPackage |
Mutation | Admin | Delete a CLI package registration. |
ensureCliPackage |
Mutation | Admin | Forces pip install git+... installation of a registered CLI package and verifies the installed version. |
The primary entry point for introducing a new skill into the system. It connects directly to a live Git remote.
mutation {
deploySkillPackage(
gitRepositoryUrl: "git@github.com:ideabosque/autonomous-integration-testing-specialist.git"
gitRef: "main"
) {
deployed
skipped
failed
}
}- Behavior: Clones the repo at
gitRef, reads everySKILL.mdfound (recursively — see "Discovery" below), calculates internal checksums, and updates the local disk cache (.hsk-versions/) and database. Re-deploying an unmodified git commit resolves to a cheapgit ls-remote(no clone) and returns that skill's name inskipped.deployed/failed/skippedare opaque JSON —deployedis a list of{skillUuid, name, version, gitRepositoryUrl, gitRef, resolvedCommit, contentChecksum, isActive},faileda list of{skill, error}; neither accepts a GraphQL sub-selection.
Executes a secure subprocess for a skill. Used heavily by Agent logic to execute associated scripts.
mutation {
runCommand(
name: "cmd-skill"
argv: ["python", "--version"]
timeoutSeconds: 30
outputLimitBytes: 20000
) {
exitCode
stdout
stderr
timedOut
truncated
}
}- Behavior: Fails securely with a
PermissionErrorif theargvdoes not strictly match an entry in the skill'sallowed_commandsarray defined inSKILL.md. Safely isolates shell injection and enforces the provided limits.
Integrates external Python packages stored on GitHub into the local environment securely.
mutation {
ensureCliPackage(packageName: "multilingual-slide-video-agent") {
packageName
version
status
error
}
}- Behavior: Checks if the previously registered
multilingual-slide-video-agentversion matches the active local environment (importlib.metadata.version). If it is missing or out of date, it triggers apip installautomatically against the registered GitHub URL.
The single entry point for an agent to actually consume the contents of a skill.
query {
skill(name: "autonomous-integration-testing-specialist") {
name
description
body
allowedCommands
cliPackages
references
gitRepositoryUrl
gitRef
resolvedCommit
staleIndex
}
}- Behavior: Resolves the skill's active version. If the active local copy on disk is missing or the internal checksum indicates drift, it automatically refreshes from Git pinned perfectly to the
resolvedCommitrecorded in the database. Returns the fullSKILL.mdbody for prompt injection, plusreferences— the resolved{path, content}list for whateverreference_files(declared or generated) resolves to.
There is no S3 (or any other) artifact store, and no ZIP-upload path, in between a skill's source and the agent that reads it:
deploySkillPackageclones the given git remote atgitRef(a branch or tag), validates eachSKILL.mdfound, and registers the resolved commit SHA (resolvedCommit) alongside the ref. Re-deploying the samegitRefis a cheap no-op: the ref is resolved to a commit viagit ls-remote(no clone) and compared against what's already registered — git is the only thing consulted to decide whether a new version exists.- Every deployed version's content is cached locally so
promoteSkillVersion/rollbackSkillcan switch versions instantly with no remote fetch. A host that never cached a given version falls back to fetching straight from git, pinned to that exact commit. - HTTPS remotes use whatever git credential helper is already configured on the host. SSH remotes (
git@host:org/repo.gitorssh://...) use the system's default SSH identity (ssh-agent/~/.ssh/config) — setHSK_GIT_SSH_KEY_PATHonly if a skill source needs a different key than your default one.
All settings can be provided via environment variables (prefix HSK_) or
passed directly to Config.initialize() as an engine setting dict.
| Setting | Required | Purpose |
|---|---|---|
HSK_SKILL_ROOT |
Yes | Folder containing skill directories. |
HSK_GIT_SSH_KEY_PATH |
No | Alternate SSH private key for git-over-SSH skill sources. Empty = use the system default identity. |
HSK_SKILL_LOCAL_METADATA_FILE |
No | Metadata filename (default .hsk-skill.json). |
HSK_SKILL_REFRESH_ON_STARTUP |
No | Refresh local cache on startup. |
HSK_ALLOW_UNREGISTERED_CHANGES |
No | Allow reading stale local checksum (default false). |
HSK_RUN_COMMAND_ENABLED |
No | Global kill switch for run_command (default false). |
HSK_RUN_COMMAND_DEFAULT_TIMEOUT_SECONDS |
No | Default timeout (default 30). |
HSK_RUN_COMMAND_OUTPUT_LIMIT_BYTES |
No | Default output cap (default 20000). |
HSK_RUN_COMMAND_WORKSPACE_ROOT |
No | Workspace root for workspace_dir scope. |
HSK_DRY_RUN |
No | Resolve and validate without executing (default false). |
OPENAI_API_KEY |
No | Enables auto-generation of missing allowed_commands/cli_packages/reference_files at deploy time (see "Auto-generated sections" below). Shared with other engines in this gateway — not HSK_-prefixed. Empty disables generation; deploys still succeed with those fields simply absent. |
OPENAI_BASE_URL |
No | Same shared setting as above. Empty = the OpenAI SDK's own default (api.openai.com). |
HSK_OPENAI_MODEL |
No | Model used for generation (default gpt-4o-mini). Harness-specific, unlike the two settings above. |
A skill is any directory (anywhere in its git repo — see "Discovery" below) containing a SKILL.md:
skills/
my-skill/
SKILL.md
scripts/
helper.py
SKILL.md uses YAML frontmatter + a markdown instruction body. Only name/description are required — leave the rest out entirely and deploy-time generation fills in what it can (see "Auto-generated sections" below):
---
name: my-skill
description: >
What the skill does and when to use it.
allowed_commands:
- argv: ["python", "scripts/helper.py"]
- argv: ["msv", "pipeline", "status"]
cli_packages:
- package_name: multilingual-slide-video-agent
git_repository_url: https://github.com/ideabosque/multilingual_slide_video_production_system.git
version: "0.1.0"
git_ref: main
reference_files:
- "notes.md"
---
You are a helpful assistant. Follow these steps...| Field | Required | Purpose |
|---|---|---|
name |
Yes | The skill's registered identity — must be unique per tenant. |
description |
Yes | Shown in searchSkills/skill results; also what agents match against. |
allowed_commands |
No | The only commands runCommand will ever execute for this skill (see "Security model" below). Omitted or empty means runCommand is fully denied for this skill. Left out of SKILL.md entirely (not even as []) and deploy-time generation may propose one — see "Auto-generated sections". |
cli_packages |
No | External Python CLI dependencies this skill needs. Each entry needs at least package_name; adding git_repository_url and version makes it auto-registered and installed the moment the skill is deployed (see "CLI package dependencies" below) — omit them if the package is already registered separately via insertUpdateCliPackage. Left out entirely, deploy-time discovery may find one already installed on the host and register it as documentation, without installing anything new. |
reference_files |
No | Paths, relative to the skill directory, whose content skill(name) returns alongside body in a references field — for prose/config the agent needs to read, never scripts. May name a path that lives elsewhere in the same repo (see "Auto-generated sections"). |
deploySkillPackage searches the whole cloned repo recursively for SKILL.md files — a skill can live at the repo root, one level down, or nested arbitrarily deep (e.g. a monorepo shaped like .claude/skills/<name>/SKILL.md). Every SKILL.md found is registered as its own skill, keyed by its own name, in a single deploy call.
allowed_commands is not a formality — it is the entire boundary between what an admin approved at deploy time and what any tenant-execute caller can trigger via runCommand at runtime:
- Empty or missing means denied, not "anything goes."
runCommandraisesPermissionErrorimmediately if a skill'sallowed_commandsis empty — there is no fallback to "allow everything." - Only exact, listed
argventries match.runCommandnever invokes a shell (shell=False) and never accepts an argv that isn't already in this list. - Only include commands you actually want a tenant-level caller able to run right now, unprompted. If a CLI package exposes a command meant to be gated behind a human decision in conversation (a publish/approve/delete-style action), leave it out of
allowed_commandseven though the package is installed and the command technically exists — installing acli_packagesdependency does not imply every one of its subcommands should be runnable. If you leaveallowed_commandsout ofSKILL.mdentirely, deploy-time generation follows this same rule when proposing one (see "Auto-generated sections") — but a generated allowlist is a best-effort proposal grounded in your skill's own wording, not a substitute for reviewing it yourself before trusting it in a shared environment.
When a cli_packages entry includes git_repository_url and version, deploySkillPackage auto-registers it (equivalent to insertUpdateCliPackage) and installs/verifies it immediately (equivalent to ensureCliPackage) as part of that same deploy call — not deferred to the first runCommand. A failed install fails only that skill's entry in the deploy response (failed), it does not abort deploying the rest of a multi-skill repo, and the skill itself is not registered if its dependency can't be installed.
There is no database-level link between a skill and a CLI package — the only association is the package_name string appearing in both the skill's SKILL.md and the hsk_cli_packages registration row, matched at read/execute time. Renaming or deleting a CLI package registration does not update or block any skill that still references its old name; the next runCommand call for that skill would simply get a "not registered" error from ensure_package.
Leave allowed_commands, cli_packages, and/or reference_files out of SKILL.md entirely (not even as []) and deploySkillPackage proposes values for whichever ones are missing. A field you did write is never touched, even if you wrote it as an empty list — generation only ever fills a key that's genuinely absent from the frontmatter. Two different mechanisms, matched to two different risk levels:
cli_packagesis discovered locally, with no LLM call at all: your skill's body text is scanned for backtick-quoted command names (`msv pipeline status`→msv), and each candidate is checked against what's actually installed on the deploying host. A name that doesn't resolve to a real installed command is dropped — nothing is invented, and nothing gets installed as a side effect of this. Everyday dev tools mentioned in passing (pip,python,git,npm,docker, ...) are ignored even when installed, since they're almost never the skill's own dependency.allowed_commands/reference_filesare proposed by an LLM (OPENAI_API_KEYrequired — see Configuration), but grounded in real, checkable state: the model sees your skill's actual body text, the real command tree of whatevercli_packagesit has (declared or discovered), and the real file list it can choosereference_filesfrom — never invents a command or a path. Everything it proposes is re-validated against that same real data afterward.
reference_files can reach outside the skill's own folder. In a monorepo where shared material (config, or a CLI dependency's own source) lives at the repo root rather than duplicated into every skill, generation is allowed to consider those files too — whatever it picks (or whatever you declared) gets copied into your skill's own installed folder automatically, so skill(name) never needs to know about the rest of the repo. SKILL.md, README.md, and anything under a docs/ or tests/ folder are never candidates.
Generated values live in a local file next to the installed SKILL.md (.hsk-generated.json) — inspect it if you want to see exactly what was proposed for your skill. It's regenerated on every deploy (never on a skipped, unchanged-commit redeploy), and a failed/misconfigured OpenAI call just leaves those fields absent rather than failing your deploy.
# Install in dev mode
pip install -e .[dev]
# Run tests
python -m pytest harness_engineering_engine/tests -v
# Type checking
mypy harness_engineering_engineMIT