Install
$ agentstack add skill-dungnotnull-vr-motion-sickness-config-agent-skill-vr-motion-sickness-config-agent-skill ✓ 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
SKILL.md - vr-motion-sickness-config Skill Registry
> Single source of truth for how skills are registered, resolved, > executed, and validated in this harness. Read this alongside > skills/manifest.json (the registry data) and config/skill_registry.py > (the registry engine). This document is the open-source operator's manual: > it tells you how to add a skill, how the DAG is enforced, what schemas a > skill must honor, and how the chain-of-thought router picks a plan.
1. What is a "skill" here?
A skill is a self-contained, prompt-defined capability declared in skills/.md and registered in skills/manifest.json. Each skill:
- has a canonical slug (matches the markdown frontmatter
name:), - owns input/output artifact schemas (validated against
assets/schemas/*.schema.json),
- may own quality gates (e.g.
G1,U1), - declares required tools and the upstream skills it depends on
(the DAG edges).
The harness is not a fixed 5-step pipeline; it is a DAG of skills that the chain-of-thought router (tools/skill_router.py) composes into a plan per request. The default plan lives in manifest.json's order field.
2. Registration
2.1 The manifest file
// skills/manifest.json
{
"version": "2.0.0",
"order": ["main", "sub-gather-requirements", "sub-evidence-collector",
"sub-core-analysis", "sub-knowledge-updater", "sub-advisor"],
"skills": [
{
"name": "sub-core-analysis",
"path": "sub-core-analysis.md",
"description": "...",
"inputs": ["requirements_record", "evidence_bundle"],
"outputs": ["comfort_config"],
"tools": ["Read", "WebSearch", "tools/ssq_scorer",
"tools/latency_auditor", "tools/comfort_matrix",
"tools/adaptation_planner"],
"gate": ["G1", "G2", "G3", "G4"],
"tags": ["analysis", "step-3"],
"requires": ["sub-gather-requirements", "sub-evidence-collector"]
}
]
}
Field rules (enforced by config/skill_registry.py and the assets/schemas/skill_manifest.schema.json schema):
| Field | Required | Rule | |-------|----------|------| | name | yes | lowercase slug, matches skills/.md frontmatter name: | | path | yes | resolved relative to skills/; must exist | | description | yes | one-line, non-empty | | inputs | optional | artifact schema names the skill consumes (validated on entry) | | outputs | optional | artifact schema names the skill produces (validated on exit) | | tools | optional | declared tools the skill may invoke | | gate | optional | quality-gate ids owned by this skill | | tags | optional | free-form tags for routing/filtering | | requires | optional | upstream skill names; must precede this skill in any plan |
2.2 Adding a new skill
- Write
skills/.mdwith frontmatter (name:,description:) and the
required sections: Role & Persona, Workflow, Tools, Output Format, Quality Gates.
- Add an entry to
skills/manifest.json(and toorderif it is part of the
default plan).
- If the skill produces a new artifact, define its JSON Schema in
config/schema.py (SCHEMAS dict) and dump it to assets/schemas/.schema.json via python -c "from config import schema; schema.dump_assets()".
- Run
python scripts/ingest_references.pyand
python tools/validate_project.py to confirm the DAG still resolves and schemas validate.
The registry is loaded lazily by get_registry() and cached process-wide; tests call reset_registry_cache() to force a reload.
3. Resolution (DAG)
SkillRegistry.resolve(plan) takes an ordered list of skill names and verifies:
- every name is registered,
- for every skill, all
requiresedges point to skills that appear earlier
in the plan (topological consistency),
- no dangling references.
Because plans are ordered, acyclicity is guaranteed by construction; the requires-precedence check enforces it. A skill whose requires edge is not yet in the plan raises SkillValidationError, which the router surfaces as a deviation in its trace.
The default plan is manifest.json["order"]; the chain-of-thought router can return a different (but still DAG-valid) plan per analysis_type.
4. Execution
from config.skill_registry import get_registry
from tools.skill_router import SkillRouter
reg = get_registry() # loads the manifest
reg.set_executor(my_executor) # my_executor(spec, context) -> dict
router = SkillRouter(reg)
result = router.execute_plan(user_request, my_executor)
# -> {"trace": ..., "results": {skill: output}, "state": {artifact: value}}
Execution contract (SkillRegistry.execute):
- Input validation - every declared
inputsartifact present in the
context is validated against its schema; missing inputs are allowed (they may be produced by an earlier step that has not run yet).
- Pre hook -
hooks.pre(spec=, context=)fires (lifecycle logging). - Executor call - the installed
executor(spec, context)returns a dict. - Output validation - every declared
outputsartifact must be present in
the result and validate against its schema; else SkillValidationError.
- Post hook -
hooks.post(spec=, context=, result=)fires. - Error hook - on any exception,
hooks.on_error(spec=, context=, error=)
fires and the exception re-raises (no silent swallow).
The shared hooks.state.StateStore carries schema-validated artifacts between steps; the router merges each skill's outputs into it so later skills see earlier artifacts. StateStore.put validates against config.schema.SCHEMAS.
In production the executor dispatches to the Claude LLM using the skill's markdown as the prompt and the prompt template in references/prompt-templates/.md as a base. In tests the executor is a pure-Python function (see scripts/run_pipeline.py simulate).
5. Validation (JSON Schemas)
| Artifact | Schema file | Produced by | |----------|-------------|-------------| | requirements_record | assets/schemas/requirements_record.schema.json | sub-gather-requirements | | evidence_bundle | assets/schemas/evidence_bundle.schema.json | sub-evidence-collector | | comfort_config | assets/schemas/comfort_config.schema.json | sub-core-analysis | | knowledge_evidence | assets/schemas/knowledge_evidence.schema.json | sub-knowledge-updater | | advisor_conclusion | assets/schemas/advisor_conclusion.schema.json | sub-advisor | | harness_result | assets/schemas/harness_result.schema.json | main | | skill_manifest | assets/schemas/skill_manifest.schema.json | the registry manifest itself | | hardware_spec | assets/schemas/hardware_spec.schema.json | the seeded HMD DB |
Schemas are defined once in config/schema.py (the importable mirror) and dumped to assets/schemas/ by config.schema.dump_assets(). The in-repo validator (config.schema.validate) implements the JSON Schema subset we use: type (incl. unions and null), required, enum, minimum/maximum, minLength/maxLength, minItems/minProperties, items, properties, additionalProperties: false, and $defs/$ref (intra-document only). It is deliberately dependency-free so the harness validates artifacts without any pip installs.
6. Input / Output JSON Schema (worked example)
requirements_record.schema.json (excerpt):
{
"type": "object",
"required": ["object", "hardware", "content_type", "user_profile",
"available_inputs", "constraints", "timeframe",
"target_audience", "language", "analysis_type", "defaults_applied"],
"properties": {
"hardware": {
"type": "object", "required": ["hmd_model"],
"properties": {
"hmd_model": {"type": "string", "minLength": 1},
"refresh_rate_hz": {"type": ["integer", "null"], "minimum": 60, "maximum": 240},
"tracking_type": {"type": ["string", "null"],
"enum": ["inside-out", "base-station", "hybrid", null]}
},
"additionalProperties": true
},
"content_type": {"type": "string",
"enum": ["fast-locomotion FPS", "cockpit", "stationary",
"360 video", "social", "rail-shooter", "mixed"]},
"language": {"type": "string", "enum": ["vi", "en"]}
},
"additionalProperties": false
}
A minimal valid instance:
{
"object": "Meta Quest 3 + Half-Life: Alyx",
"hardware": {"hmd_model": "Meta Quest 3"},
"content_type": "fast-locomotion FPS",
"user_profile": {"experience": "none", "prior_sickness": "none"},
"available_inputs": {},
"constraints": {"multiplayer": false},
"timeframe": "2 weeks",
"target_audience": "end-user",
"language": "en",
"analysis_type": "combined",
"defaults_applied": []
}
Validate it in code:
from config import schema
schema.validate(instance, schema.REQUIREMENTS_RECORD)
# raises schema.ValidationError with a path on failure
schema.is_valid(instance, schema.REQUIREMENTS_RECORD) # -> bool
7. Tools (rich tool definitions)
Each domain calculator is a registered ToolSpec with an input JSON Schema, an output JSON Schema, and a deterministic Python handler. The ToolRegistry.invoke(name, input) validates the input, calls the handler, and validates the output.
| Tool name | Description | Tags | |-----------|-------------|------| | ssq.score | Score a Simulator Sickness Questionnaire (Kennedy 1993) | ssq, g1, diagnostic | | g1.audit | Audit HMD/runtime against comfort thresholds (G1) | g1, hardware, audit | | g2.comfort_matrix | Select G2 comfort options (honors multiplayer) | g2, comfort | | g4.adaptation_plan | Build a G4 14-day adaptation plan or veteran exemption | g4, adaptation |
from tools.tool_registry import get_registry
reg = get_registry()
reg.invoke("ssq.score", {"responses": {"nausea": 2, "vertigo": 1}})
# -> {"N": ..., "O": ..., "D": ..., "total": ..., "severity_band": ...}
To add a tool: create tools/.py, define input/output schemas, a handler, and call register_tool(...) at import time; the tool registry auto- loads it via get_registry().
8. Hooks (lifecycle, state, events)
hooks.lifecycle.LifecycleHooks- thepre/post/on_error/on_event
protocol the registry calls.
hooks.lifecycle.CompositeHooks- fan-out to multiple hooks.hooks.lifecycle.LoggingHooks- structured, low-noise logging of every
skill execution (duration, inputs, outputs, errors).
hooks.state.StateStore- thread-safe, schema-aware artifact store shared
across skills; put validates against the schema registry.
hooks.events.EventEmitter- pub/sub forstep.started/step.completed
/ gate.failed / degradation.level / knowledge.gap events.
Wire hooks into the registry with registry.set_hooks(composite).
9. Chain-of-thought router
tools/skill_router.SkillRouter.route(user_request) returns a RouterTrace with the selected plan, the reasoning steps, any deviations, and notes. The plan is always validated against the registry DAG before use. Four analysis_type plans ship by default (combined, hardware-only, content-design, adaptation-plan); all are DAG-valid (every skill's requires edges precede it). The router is the seam where future model-driven plan selection would plug in; today it is deterministic and auditable.
10. Quality gates
Universal gates U1-U6 plus domain gates G1-G4 are owned by skills per the manifest's gate field and enforced by skills/main.md. The registry does not itself enforce gates; it exposes which skill owns which gate (registry.by_gate("G1")) so the harness quality-gate review can attribute failures. The hard contract (disclosure precedes recommendation, exactly one verdict category, evidence tiers per source) lives in the skill markdown and the advisor_conclusion / harness_result schemas.
11. Operator quickstart
# 1. environment + readiness
python scripts/setup_local.py
# 2. seed/verify the knowledge base baseline
python scripts/seed_knowledge_base.py
# 3. ingest references + assets + manifest
python scripts/ingest_references.py
# 4. inspect the registry / plan / tools
python scripts/run_pipeline.py manifest
python scripts/run_pipeline.py plan combined
python scripts/run_pipeline.py tools
# 5. run the domain calculators standalone
python scripts/run_pipeline.py ssq --% --responses "{\"nausea\":2,\"vertigo\":1}"
python scripts/run_pipeline.py g1 --% --hardware "{\"hmd_model\":\"Meta Quest 3\",\"refresh_rate_hz\":90,\"mtp_latency_ms\":18,\"reprojection\":\"ASW 2.0\",\"ipd_mm\":64,\"ipd_method\":\"hardware\",\"tracking_type\":\"inside-out\",\"render_scale\":1.0}"
python scripts/run_pipeline.py g2 --% --request "{\"content_type\":\"fast-locomotion FPS\",\"user_profile\":{\"experience\":\"none\",\"prior_sickness\":\"none\"},\"constraints\":{\"multiplayer\":true}}"
python scripts/run_pipeline.py g4 --% --profile "{\"experience\":\"none\",\"prior_sickness\":\"occasional\"}"
# 6. prove the full DAG wiring end-to-end (mock executor, no LLM)
python scripts/run_pipeline.py simulate combined
# 7. validators (open-source CI gate)
python tools/validate_project.py
python tools/test_knowledge_updater.py
python tools/run_test_scenarios.py --all
12. File map
vr-motion-sickness-config/
+-- SKILL.md <- this registry manual
+-- CLAUDE.md / README.md / PROJECT-detail.md / PROJECT-DEVELOPMENT-PHASE-TRACKING.md
+-- SECOND-KNOWLEDGE-BRAIN.md
+-- conftest.py <- puts project root on sys.path
+-- requirements.txt / LICENSE / .gitignore
+-- config/
| +-- __init__.py / settings.py / schema.py / skill_registry.py
+-- hooks/
| +-- __init__.py / lifecycle.py / state.py / events.py
+-- tools/
| +-- tool_registry.py / ssq_scorer.py / latency_auditor.py
| +-- comfort_matrix.py / adaptation_planner.py / skill_router.py
| +-- structured_logging.py / context_manager.py / error_handler.py
| +-- hardware_db.py
| +-- knowledge_updater.py / test_knowledge_updater.py
| +-- run_test_scenarios.py / validate_project.py
+-- skills/
| +-- manifest.json / main.md / sub-*.md
+-- references/
| +-- domain-guidelines.md / hardware-specs.json / prompt-templates/*.md
+-- assets/
| +-- schemas/*.schema.json / diagrams/architecture.md
+-- scripts/
| +-- setup_local.py / seed_knowledge_base.py / ingest_references.py / run_pipeline.py
+-- tests/
+-- test-scenarios.md / TEST_RESULTS.md
+-- logs/ <- runtime logs (knowledge_update.log, ...)
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: dungnotnull
- Source: dungnotnull/vr-motion-sickness-config-agent-skill
- License: MIT
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.