Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .agents/plugins/marketplace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "nf-core-agents",
"interface": {
"displayName": "nf-core Skills"
},
"plugins": [
{
"name": "nf-core-tools",
"source": {
"source": "local",
"path": "./plugins/nf-core-tools"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Developer Tools"
}
]
}
16 changes: 16 additions & 0 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "https://json.schemastore.org/claude-code-marketplace.json",
"name": "nf-core-agents",
"owner": {
"name": "nf-core",
"url": "https://nf-co.re"
},
"plugins": [
{
"name": "nf-core-tools",
"source": "./plugins/nf-core-tools",
"description": "Cross-agent nf-core checks and workflow guardrails for nf-core projects",
"version": "0.1.0"
}
]
}
63 changes: 63 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "scripts/prek-hooks/claude/guard-nfcore-modules.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "scripts/prek-hooks/claude/lint-schema.sh"
}
]
},
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "scripts/prek-hooks/claude/check-param-drift.sh"
}
]
},
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "scripts/prek-hooks/claude/lint-local-module.sh"
}
]
},
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "scripts/prek-hooks/claude/check-nftest-exists.sh"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "scripts/prek-hooks/check-changelog.sh"
}
]
}
]
}
}
18 changes: 18 additions & 0 deletions .cursor-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "nf-core-agents",
"owner": {
"name": "nf-core",
"email": "infrastructure@nf-co.re"
},
"metadata": {
"description": "Agent skills and workflow guardrails for nf-core projects.",
"version": "0.1.0"
},
"plugins": [
{
"name": "nf-core-tools",
"source": "./plugins/nf-core-tools",
"description": "Cross-agent nf-core checks and workflow guardrails powered by shared prek hooks."
}
]
}
10 changes: 10 additions & 0 deletions .github/workflows/prek.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name: Prek checks

on: [push, pull_request]

jobs:
prek:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: j178/prek-action@v2
9 changes: 9 additions & 0 deletions .markdownlint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"default": true,
"MD013": false,
"MD024": {
"siblings_only": true
},
"MD033": false,
"MD041": false
}
23 changes: 23 additions & 0 deletions docs/AGENT_HOOKS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Agent hook provider notes

This repo keeps nf-core validation policy provider-neutral in `scripts/agent_hooks/`.
Provider-specific hook formats belong in adapter modules under
`scripts/agent_hooks/providers/`.

## Internal contract

The internal interface is a phase report, not a provider wire format:

```python
report = run_phase("stop", files)
```

Provider adapters translate that report into each agent runtime's required stdout,
stderr, and exit-code behavior.

## Provider shape references

- [Codex](agent-hooks/codex.md)
- [Claude Code](agent-hooks/claude.md)
- [Cursor](agent-hooks/cursor.md)
- [Generic exit-code providers](agent-hooks/generic.md)
57 changes: 57 additions & 0 deletions docs/agent-hooks/claude.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Claude Code hook provider shape

Claude Code uses JSON stdin for hook events and supports structured JSON stdout
for decisions on blocking-capable events.

## Stop input shape

Claude Code `Stop` input is JSON on stdin. Relevant fields include:

```json
{
"hook_event_name": "Stop",
"session_id": "...",
"transcript_path": "/path/to/transcript.jsonl",
"cwd": "/path/to/project",
"stop_hook_active": false,
"last_assistant_message": "...",
"background_tasks": [],
"session_crons": []
}
```

Important fields for this repo:

- `cwd`
- `hook_event_name`
- `stop_hook_active`
- `last_assistant_message`

## Stop output shape

For `Stop`, block with clean JSON on stdout:

```json
{
"decision": "block",
"reason": "Continue fixing before stopping."
}
```

Allow stopping with:

```json
{
"decision": "approve",
"reason": "nf-core stop hook: checks passed"
}
```

## Rules and gotchas

- Use stdout for the structured response.
- Keep stdout clean JSON; send harness logs to stderr.
- The adapter should return exit code `0` when expressing a structured block.
- If `stop_hook_active` is true, avoid recursive blocking.
- `SessionEnd` is not a substitute for `Stop` because it does not provide the
same blocking control.
102 changes: 102 additions & 0 deletions docs/agent-hooks/codex.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Codex hook provider shape

Source of truth: OpenAI Codex sources in `openai/codex`:

- `docs/config.md`
- `codex-rs/hooks/src/lib.rs`
- `codex-rs/hooks/src/events/stop.rs`
- `codex-rs/hooks/src/engine/output_parser.rs`
- `codex-rs/hooks/schema/generated/stop.command.input.schema.json`
- `codex-rs/hooks/schema/generated/stop.command.output.schema.json`
- `codex-rs/config/src/hook_config.rs`

## Events

Codex hook events include:

- `PreToolUse`
- `PermissionRequest`
- `PostToolUse`
- `PreCompact`
- `PostCompact`
- `SessionStart`
- `UserPromptSubmit`
- `SubagentStart`
- `SubagentStop`
- `Stop`

## nf-core hook manifest

The Codex plugin manifest points at `plugins/nf-core-tools/hooks/codex.json`.
That file uses Codex event names and nested command hook entries.

## Hook config shape

```json
{
"hooks": {
"Stop": [
{
"matcher": null,
"hooks": [
{
"type": "command",
"command": "...",
"timeout": 600,
"statusMessage": "..."
}
]
}
]
}
}
```

## Stop input shape

Codex `Stop` input is JSON on stdin:

```json
{
"hook_event_name": "Stop",
"cwd": "/path/to/project",
"session_id": "...",
"turn_id": "...",
"transcript_path": null,
"model": "...",
"permission_mode": "default",
"stop_hook_active": false,
"last_assistant_message": null
}
```

Important fields for this repo:

- `cwd`
- `hook_event_name`
- `stop_hook_active`
- `last_assistant_message`

## Stop output shape

Codex `Stop` output can block with clean JSON on stdout:

```json
{
"decision": "block",
"reason": "Continue fixing before stopping."
}
```

A successful no-block response can be empty stdout or structured JSON without a
block decision. This repo prefers structured JSON for provider adapters.

## Rules and gotchas

- `decision: "block"` requires a non-empty `reason`.
- stdout must be valid hook JSON when using JSON output; route harness logs to stderr.
- Exit code `2` plus stderr is also treated as a continuation/block prompt.
- Other nonzero exits are hook failures, not normal block decisions.
- If `stop_hook_active` is true, avoid blocking again to prevent recursive stop loops.
- Keep a distinct Codex adapter even if it initially resembles Claude. Future
`PreToolUse`, `PermissionRequest`, and `PostToolUse` semantics differ.
Loading
Loading