Install
$ agentstack add skill-aspenkit-aspens-doc-sync ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
You are working on doc-sync, the incremental skill update command (aspens doc sync).
Key Concepts
- Monorepo-aware:
getGitRoot(repoPath)resolves the actual git root.projectPrefix(toGitRelative) computes the subdirectory offset.scopeProjectFiles()filters changed files to the project subdirectory. Diffs are fetched fromgitRootbut file paths are project-relative. - Multi-target publish:
configuredTargets()reads.aspens.jsonfor all configured targets.chooseSyncSourceTarget()picks the best source (prefers Claude if both exist). LLM generates for the source target;publishFilesForTargets()transforms output for all other configured targets.graphSerializedandrepoPathare passed through to the transform context for conditional architecture references and disk-based instructions file loading. - Backend routing:
runLLM()fromrunner.jsdispatches torunClaude()orrunCodex()based onconfig.backend(defaults to source target's id). - Diff-based flow: Gets
git diff HEAD~N..HEADfrom git root, scopes changed files to project prefix, then feeds diff plus existing skill contents and graph context to the selected backend. - Changetype filter (Phase 1):
isNoOpDiff()fromdiff-classifier.jsskips the LLM call entirely on lockfile-only diffs and diffs touching zero code-bearing files.LOCK_FILESandCODE_BEARING_EXTSare the source of truth — extend them here, not at call sites. - Prompt path variables: Passes
{ skillsDir, skillFilename, instructionsFile, configDir }from source target toloadPrompt()for path substitution in prompts. - Refresh mode (
--refresh): Skips diff entirely. Reviews every skill against the current codebase. Base skill refreshed first, then domain skills in parallel batches ofPARALLEL_LIMIT(3). Also refreshes instructions file and reports uncovered domains. Refresh mode runsensureRootKeyFilesSection(legacy stripper) beforesyncSkillsSectionso any leftover## Key Filesblocks from old docs are removed. - Deterministic section repair:
repairDeterministicSections()runs a no-LLM pass that re-injects## Skillsand## Behaviorinto the root instructions file from on-disk state and strips any legacy## Key Filesblock viaensureRootKeyFilesSection. Called from the no-op / "up to date" sync paths so missing-section drift is fixed every invocation. The normal sync flow also runs the same Skills + Behavior + legacy-strip block on the canonical instructions file after the LLM step. - Graph rebuild on every sync: Calls
buildRepoGraph+persistGraphArtifacts(with source target) to keep graph fresh.graphSerializedreturn value is captured and forwarded topublishFilesForTargetsfor conditional Codex architecture refs. Graph failure is non-fatal. - Legacy v0.7 hub-block cleanup:
notifyLegacyHubBlockIfPresent()surfaces a one-line notice on the first sync after upgrade whenCLAUDE.md/AGENTS.mdstill carries the legacy## Key Fileshub-counts block, so the diff that strips it isn't alarming.regenerateStaleCodeMap()force-rebuilds.claude/code-map.mdon no-op syncs when it still carries the legacy**Hub files**block. - Graceful response handling: After LLM returns, if output has content but no `` tags, treats it as "no updates needed" with a verbose-only warning. The prompt explicitly requests an empty response when nothing needs updating.
- Graph-aware skill mapping:
mapChangesToSkills()checks direct file matches viafileMatchesActivation()(fromskill-reader.js) and also whether changed files are imported by files matching a skill's activation block. - Interactive file picker: When diff exceeds 80k chars and TTY is available, offers multiselect with skill-relevant files pre-selected.
- Prioritized diff:
buildPrioritizedDiff()gives skill-relevant files 60k char budget, everything else 20k (80k total). Cuts atdiff --gitboundaries. - Token optimization: Affected skills sent in full; non-affected skills send only path + description line.
- Split writes: Direct-write files (
.claude/,CLAUDE.md, rootAGENTS.md) usewriteSkillFiles(). Directory-scopedAGENTS.mdfiles (e.g.src/AGENTS.md) usewriteTransformedFiles(). - Skill-rules regeneration: After writing, regenerates
skill-rules.jsonviaextractRulesFromSkills()— only for targets withsupportsHooks: true(Claude). UseshookTargetfrom publish targets list. findExistingSkillsis target-aware: Usestarget.skillsDirandtarget.skillFilenameto locate skills for any target.- Git hook (monorepo-aware):
installGitHook()installs at the git root with per-project scoping. Hook usesPROJECT_PATHderived from project-relative offset. Each subproject gets its own labeled hook block (# >>> aspens doc-sync hook (label) >>>) with a unique function name (__aspens_doc_sync_). Multiple subprojects can coexist in one post-commit hook. Hook skips aspens-only commits scoped to the project prefix. 5-minute per-project cooldown via/tmp/aspens-sync-.lock; logs to/tmp/aspens-sync-.log(truncated to last 100 lines past 200). Unlabeled v0.6-era blocks are auto-upgraded on re-install. - Force writes: doc-sync always calls
writeSkillFileswithforce: true.
Critical Rules
runLLMis called withallowedTools: ['Read', 'Glob', 'Grep']— doc-sync must never grant write tools.parseOutputrestricts paths based ongetAllowedPaths([sourceTarget])— paths outside the allowed set are silently dropped.- Unparseable output is a soft warning — if LLM returns text without any `` tags, doc-sync logs a verbose warning and treats it as "no updates needed" instead of throwing.
getGitDiffgracefully falls back from N commits to 1 if fewer available.actualCommitstracks what was used.- The command exits early with
CliErrorif the source target's skills directory doesn't exist. checkMissingHooks()inbin/cli.jsonly checks for Claude skills (not Codex — Codex doesn't use hooks).dedupeFiles()ensures no duplicate paths when publishing across multiple targets.- Git operations use
gitRoot— diffs, logs, and changed files are fetched from git root, notrepoPath. File paths are then scoped viaprojectPrefix. diff-classifier.jsis a leaf module —graph-builder.jsimportsLOCK_FILESfrom it; never import fromgraph-builderback into the classifier.
References
- Patterns:
src/lib/skill-reader.js—GENERIC_PATH_SEGMENTS,fileMatchesActivation(),getActivationBlock()
Last Updated: 2026-05-11
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: aspenkit
- Source: aspenkit/aspens
- License: MIT
- Homepage: https://www.npmjs.com/package/aspens
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.