Define named focus entries that combine a profile with a prompt for repeatable, non-interactive AI execution. Focus entries are the bridge between harness configuration and CI automation. They can also serve as the source of an agent-driven sensor — referenced by name or inlined inside the sensor.
# Clean up from any previous run
rm -rf /tmp/ynh-tutorial
ynh uninstall local/focus-demo 2>/dev/null
mkdir -p /tmp/ynh-tutorialCreate a harness with profiles and focus entries that reference them:
mkdir -p /tmp/ynh-tutorial/focus-harness/skills/deploy
mkdir -p /tmp/ynh-tutorial/focus-harness/.ynh-plugin
cat > /tmp/ynh-tutorial/focus-harness/.ynh-plugin/plugin.json << 'EOF'
{
"$schema": "https://eyelock.github.io/ynh/schema/plugin.schema.json",
"name": "focus-demo",
"version": "0.1.0",
"default_vendor": "claude",
"hooks": {
"after_tool": [
{ "command": "/usr/local/bin/format-check.sh" }
]
},
"mcp_servers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" }
}
},
"profiles": {
"ci": {
"hooks": {
"before_tool": [
{ "matcher": "Bash", "command": "/usr/local/bin/ci-guard.sh" }
]
},
"mcp_servers": {
"github": null
}
}
},
"focuses": {
"review": {
"profile": "ci",
"prompt": "Review staged changes for quality and correctness"
},
"docs": {
"prompt": "Generate API documentation for all public interfaces"
}
}
}
EOF
cat > /tmp/ynh-tutorial/focus-harness/instructions.md << 'EOF'
You are a development assistant. Follow team coding standards.
EOF
cat > /tmp/ynh-tutorial/focus-harness/skills/deploy/SKILL.md << 'EOF'
---
name: deploy
description: Deploy to staging or production
---
Run the deployment pipeline for the target environment.
EOFKey points:
focusis a top-level field alongsideprofiles- Each focus has a
prompt(required) and optionalprofile - The
reviewfocus activates theciprofile and sends a review prompt - The
docsfocus has no profile — it uses the base configuration - The
ciprofile usesnullto remove the inheritedgithubMCP server
ynd validate /tmp/ynh-tutorial/focus-harnessExpected:
/tmp/ynh-tutorial/focus-harness: valid
The validator checks that each focus entry has a non-empty prompt and that any referenced profile exists.
ynd preview /tmp/ynh-tutorial/focus-harness -v claude --focus reviewExpected output includes:
.claude/hooks/hooks.jsonwith theciprofile'sbefore_toolhook (PreToolUse) and the inherited baseafter_toolhook (PostToolUse) — profiles use merge semantics- No
.claude/.mcp.json— theciprofile removes thegithubMCP server vianull
Compare with --focus docs (no profile, uses base config):
ynd preview /tmp/ynh-tutorial/focus-harness -v claude --focus docsExpected: .claude/hooks/hooks.json has only the base after_tool hook (PostToolUse). .claude/.mcp.json has the github MCP server (inherited from base).
ynd preview /tmp/ynh-tutorial/focus-harness -v claude --focus review --profile ciExpected error:
Error: cannot use --focus and --profile together
A focus already includes a profile — specifying both is ambiguous.
ynd preview /tmp/ynh-tutorial/focus-harness -v claude --focus nonexistentExpected error:
Error: focus "nonexistent" not defined in harness
The YNH_FOCUS environment variable activates a focus without the flag:
YNH_FOCUS=review ynd preview /tmp/ynh-tutorial/focus-harness -v claudeExpected: same output as --focus review — the ci profile's hooks merged with base, no MCP servers.
ynh install /tmp/ynh-tutorial/focus-harness
ynh info local/focus-demoExpected output includes a Focus: section:
Focus:
docs (default) "Generate API documentation for all public interfaces"
review profile=ci "Review staged changes for quality and correctness"
And a Profiles: section:
Profiles:
ci hooks: before_tool mcp_servers: github
Hand-editing the manifest is fine for an author. For an interactive consumer (TermQ, scripts, ad-hoc tweaks) the CLI provides the same surface:
# Add a focus
ynh focus add /tmp/ynh-tutorial/focus-harness security "audit this PR for security issues" --profile ci
# Update prompt or profile binding
ynh focus update /tmp/ynh-tutorial/focus-harness security --prompt "audit thoroughly for security issues"
ynh focus update /tmp/ynh-tutorial/focus-harness security --clear-profile
# Remove a focus
ynh focus remove /tmp/ynh-tutorial/focus-harness security--profile and --clear-profile are mutually exclusive on update. Adding a focus that references a profile name not defined in the manifest is rejected with an error. Removing a profile referenced by any focus is also rejected (the focus has to be updated or removed first) — see Tutorial 13: Profiles §"Edit profiles from the command line".
The first positional argument is either a filesystem path (as above, while authoring) or a canonical id (local/focus-demo, github.com/<org>/<repo>/<name>) once the harness is installed.
ynh uninstall local/focus-demo 2>/dev/null
rm -rf /tmp/ynh-tutorial- Focus entries combine a profile + prompt for repeatable AI execution
- Each focus requires a
prompt; theprofilefield is optional --focus <name>activates a focus onynh run,ynd preview,ynd diff, andynd exportYNH_FOCUSenv var activates a focus (flag takes precedence)--focusand--profileare mutually exclusive — focus already includes a profile- Focus entries that reference a non-existent profile are caught by
ynd validate ynh infodisplays focus entries and profiles- Focuses can be edited with
ynh focus add/remove/update— the same surface a GUI consumer drives
Tutorial 8: Project-Local Config — use .ynh-plugin/plugin.json in your project root for zero-install AI configuration.