Install
$ agentstack add skill-pwnote-skills-pwnote-engagement-file ✓ 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
Security
This skill describes the engagement file schema for data transfer between pwnote instances. Follow these rules:
- Never output real credential
secretvalues anywhere — use `` as placeholder - Never log, echo, or print plaintext secrets
- Treat
requestBody,requestHeaders,responseBodyfields as potentially sensitive — redact before sharing externally - The
secretfield in credential blocks is populated from user-provided data, never generated by the agent
Installation
npx skills add Pwnote/skills
Pwnote Engagement File Format
Reference for creating or editing pwnote engagement import/export JSON files. A valid file contains all data for one pentest engagement and can be imported via Settings → Import or the workspace Import button.
File Structure
{
"engagement": { ... },
"docs": [ ... ],
"blocks": [ ... ],
"findings": [ ... ],
"boards": [ ... ],
"boardNodes": [ ... ],
"boardEdges": [ ... ],
"activity": [ ... ]
}
All top-level keys are required but may be empty arrays.
Field Reference
engagement (object)
| Field | Type | Required | Description | |-------|------|----------|-------------| | name | string | yes | Engagement name, e.g. "Q4External2026" | | client | string | yes | Client name, e.g. "Acme Corp" | | testType | string | yes | One of: "black-box", "grey-box", "white-box" | | scope | string[] | yes | IPs, domains, CIDRs, app URLs | | roe | string | no | Rules of engagement as free text | | startDate | string | yes | ISO date "YYYY-MM-DD" | | endDate | string | yes | ISO date "YYYY-MM-DD" | | testers | string[] | yes | Operator names/handles | | archived | boolean | yes | false for new engagements |
Generated fields (omit — set on import): id, createdAt, updatedAt.
docs (array of objects)
| Field | Type | Required | Description | |-------|------|----------|-------------| | title | string | yes | Doc name, e.g. "01_Recon" | | order | number | yes | Sort order within engagement | | parentId | string | no | Parent doc ID for folder nesting | | folder | boolean | no | true if this doc is a folder |
Generated fields: id, engagementId, createdAt, updatedAt.
blocks (array of objects)
Each block has these base fields plus type-specific fields:
Base fields (all block types): | Field | Type | Required | Description | |-------|------|----------|-------------| | type | string | yes | Block type discriminator (see below) | | docId | string | yes | Must match a doc id in the file | | order | number | yes | Sort order within doc | | tags | string[] | no | Tag labels, e.g. ["nmap", "discovery"] |
Generated fields: id.
Type-specific fields:
"heading" — Section header | Field | Type | Required | Description | |-------|------|----------|-------------| | level | number | yes | 1, 2, or 3 | | text | string | yes | Heading text |
Use level: 1 for document titles, level: 2 for major sections, level: 3 for sub-sections. Always use a mix of levels for structure — never use only level 1.
"paragraph" — Plain text | Field | Type | Required | Description | |-------|------|----------|-------------| | text | string | yes | Paragraph content |
"markdown" — Rich text block | Field | Type | Required | Description | |-------|------|----------|-------------| | markdown | string | yes | Markdown content |
"code" — Code snippet | Field | Type | Required | Description | |-------|------|----------|-------------| | language | string | yes | e.g. "bash", "python3", "rust", "go", "javascript", "typescript", "sql", "yaml" | | code | string | yes | Code content |
"command-output" — Shell command and its output | Field | Type | Required | Description | |-------|------|----------|-------------| | command | string | yes | The command run | | output | string | yes | Command output text | | timestamp | string | no | ISO timestamp |
"host" — Host/asset entry | Field | Type | Required | Description | |-------|------|----------|-------------| | ip | string | yes | IP address | | hostname | string | no | DNS name | | os | string | no | Operating system | | ports | string[] | yes | Port list, e.g. ["22/tcp", "80/tcp", "443/tcp"] | | notes | string | no | Free-text notes |
"credential" — Credential (sensitive). The secret field must use ` when demonstrating — never output real values. | Field | Type | Required | Description | |-------|------|----------|-------------| | username | string | yes | Username | | secret | string | yes | in examples; real values come from user-provided data only | | secretType | string | yes | One of: "password", "hash", "token", "key" | | source | string | no | Where credential was found | | sensitive | boolean | yes | Always true` |
"screenshot" — Image evidence | Field | Type | Required | Description | |-------|------|----------|-------------| | dataUrl | string | no | Base64 data URL of image | | caption | string | no | Image caption |
"checklist" — Task checklist | Field | Type | Required | Description | |-------|------|----------|-------------| | title | string | yes | Checklist title | | items | array | yes | Array of { id: string, text: string, done: boolean } |
"timeline" — Timeline event | Field | Type | Required | Description | |-------|------|----------|-------------| | timestamp | string | yes | ISO datetime | | event | string | yes | Event description | | actor | string | no | Who performed the action |
"table" — Data table | Field | Type | Required | Description | |-------|------|----------|-------------| | headers | string[] | yes | Column headers | | rows | array | yes | Array of string arrays (cells) |
"separator" — Visual divider No extra fields beyond base.
"http-request" — HTTP request/response pair | Field | Type | Required | Description | |-------|------|----------|-------------| | method | string | yes | HTTP method: "GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS" | | url | string | yes | Request URL | | requestHeaders | string | yes | Raw request headers (one per line) | | requestBody | string | yes | Request body | | responseStatus | number | yes | HTTP status code (0 if no response) | | responseHeaders | string | yes | Raw response headers (one per line) | | responseBody | string | yes | Response body |
"finding" — Linked finding (references a finding by ID) | Field | Type | Required | Description | |-------|------|----------|-------------| | findingId | string | yes | Must match a finding id in the file |
findings (array of objects)
| Field | Type | Required | Description | |-------|------|----------|-------------| | title | string | yes | Finding title | | severity | string | yes | One of: "critical", "high", "medium", "low", "info" | | cvssScore | number | no | 0.0–10.0 | | cvssVector | string | no | CVSS vector string | | cwe | string | no | CWE identifier, e.g. "CWE-79" | | cve | string | no | CVE identifier, e.g. "CVE-2024-12345" | | affectedAssets | string[] | yes | Affected hosts/URLs | | description | string | yes | Vulnerability description | | poc | string | yes | Proof of concept | | remediation | string | yes | Fix guidance | | references | string[] | yes | URLs to references | | status | string | yes | One of: "draft", "confirmed", "fixed", "accepted-risk", "needs-retest" | | retestResult | string | no | Outcome of retest | | tags | string[] | yes | Tag labels |
Generated fields: id, engagementId, createdAt, updatedAt.
boards (array of objects)
| Field | Type | Required | Description | |-------|------|----------|-------------| | name | string | yes | Board name, e.g. "Topology" | | kind | string | yes | One of: "topology", "killchain", "planning", "forensics", "retest", "post-exploitation", "custom" | | locked | boolean | no | true to lock board from edits |
Generated fields: id, engagementId, createdAt, updatedAt.
boardNodes (array of objects)
| Field | Type | Required | Description | |-------|------|----------|-------------| | refType | string | yes | One of: "host", "finding", "credential", "freeform" | | refId | string | no | Links to block/finding ID (null for freeform) | | x | number | yes | Flow canvas X position | | y | number | yes | Flow canvas Y position | | data | object | no | Extra node data (label for freeform, ip/ports for host, etc.) | | boardId | string | yes | Must match a board id in the file |
Generated fields: id.
boardEdges (array of objects)
| Field | Type | Required | Description | |-------|------|----------|-------------| | source | string | yes | Source boardNode id | | target | string | yes | Target boardNode id | | label | string | no | Edge label (e.g. "credential" for cred edges) | | boardId | string | yes | Must match a board id in the file |
Generated fields: id.
activity (array of objects)
| Field | Type | Required | Description | |-------|------|----------|-------------| | actor | string | yes | Who performed the action | | kind | string | yes | Activity kind, e.g. "engagement.create", "block.create", "finding.status" | | message | string | yes | Human-readable description | | meta | object | no | Extra metadata |
Generated fields: id, engagementId, timestamp.
ID Linking Rules
IDs in export files are local references. The import process regenerates all IDs but preserves the relationship graph by remapping foreign keys automatically. Use any ID pattern you like (e.g. tmp_doc_recon, tmp_f_xss, tmp_bn_host1).
All cross-references MUST point to IDs defined within the same JSON file. The import remaps them to the newly generated IDs so links survive the import intact.
| Foreign Key | Points To | Field Location | |-------------|-----------|----------------| | block.docId | doc id | every block | | block.findingId | finding id | finding-type blocks only | | boardNode.boardId | board id | every boardNode | | boardNode.refId | block id or finding id | host/finding/credential nodes | | boardEdge.source | boardNode id | every boardEdge | | boardEdge.target | boardNode id | every boardEdge | | boardEdge.boardId | board id | every boardEdge |
Freeform nodes have refId: null (no link to any block/finding).
Node Linking Example
To display a host and linked finding on a topology board:
{
"docs": [{ "id": "tmp_doc_recon", "title": "01_Recon", "order": 0 }],
"blocks": [
{
"id": "tmp_b_host1", "docId": "tmp_doc_recon", "order": 0, "tags": [],
"type": "host", "ip": "10.0.0.1", "hostname": "web.example.com",
"os": "Ubuntu 22.04", "ports": ["22/tcp", "80/tcp", "443/tcp"]
},
{
"id": "tmp_b_finding1", "docId": "tmp_doc_recon", "order": 1, "tags": ["web"],
"type": "finding", "findingId": "tmp_f_xss"
}
],
"findings": [
{
"id": "tmp_f_xss", "title": "Reflected XSS",
"severity": "high", "cvssScore": 6.1, "...": "..."
}
],
"boards": [
{ "id": "tmp_brd_topology", "name": "Topology", "kind": "topology" }
],
"boardNodes": [
{
"id": "tmp_bn_host1", "boardId": "tmp_brd_topology",
"refType": "host", "refId": "tmp_b_host1",
"x": 100, "y": 100,
"data": { "ip": "10.0.0.1", "hostname": "web.example.com", "ports": ["22/tcp", "80/tcp", "443/tcp"] }
},
{
"id": "tmp_bn_finding1", "boardId": "tmp_brd_topology",
"refType": "finding", "refId": "tmp_f_xss",
"x": 350, "y": 100,
"data": { "title": "Reflected XSS", "severity": "high", "cvssScore": 6.1 }
}
],
"boardEdges": [
{
"id": "tmp_be_1", "boardId": "tmp_brd_topology",
"source": "tmp_bn_host1", "target": "tmp_bn_finding1",
"label": "exploits"
}
]
}
Key rules for node data:
hostnodes:datamust includeip,hostname,portsfindingnodes:datamust includetitle,severity,cvssScorecredentialnodes:datamust includeusername,secretTypefreeformnodes:datamust includelabel(display text)- Edges between credential and host nodes should use
label: "credential"for visual styling
Example: Minimal Engagement
{
"engagement": {
"name": "External Pentest Q4",
"client": "Example Corp",
"testType": "grey-box",
"scope": ["10.0.0.0/24", "app.example.com"],
"roe": "Testing window: 09-18 local.\nExclusions: production DB.",
"startDate": "2026-07-21",
"endDate": "2026-08-04",
"testers": ["operator"],
"archived": false
},
"docs": [
{ "id": "tmp_doc_recon", "title": "01_Recon", "order": 0, "engagementId": "tmp_eng" },
{ "id": "tmp_doc_exploit", "title": "02_Exploitation", "order": 1, "engagementId": "tmp_eng" }
],
"blocks": [
{
"id": "tmp_b_host1", "docId": "tmp_doc_recon", "order": 0, "tags": [],
"type": "host", "ip": "10.0.0.1", "hostname": "web.example.com", "os": "Ubuntu 22.04",
"ports": ["22/tcp", "80/tcp", "443/tcp"]
},
{
"id": "tmp_b_finding1", "docId": "tmp_doc_exploit", "order": 0, "tags": ["web"],
"type": "finding", "findingId": "tmp_f_xss"
},
{
"id": "tmp_b_sep1", "docId": "tmp_doc_recon", "order": 1, "tags": [],
"type": "separator"
},
{
"id": "tmp_b_code1", "docId": "tmp_doc_exploit", "order": 1, "tags": [],
"type": "code", "language": "python3", "code": "print('hello')"
}
],
"findings": [
{
"id": "tmp_f_xss",
"title": "Reflected XSS in search endpoint",
"severity": "high",
"cvssScore": 6.1,
"affectedAssets": ["app.example.com/search"],
"description": "The search parameter is reflected without sanitization.",
"poc": "alert(1)",
"remediation": "Encode HTML entities in the response.",
"references": ["https://owasp.org/www-community/attacks/xss/"],
"status": "confirmed",
"tags": ["xss", "web"]
}
],
"boards": [
{
"id": "tmp_brd_topology",
"name": "Topology", "kind": "topology", "locked": false,
"engagementId": "tmp_eng", "createdAt": 0, "updatedAt": 0
}
],
"boardNodes": [
{
"id": "tmp_bn_host1", "boardId": "tmp_brd_topology",
"refType": "host", "refId": "tmp_b_host1",
"x": 100, "y": 100,
"data": { "ip": "10.0.0.1", "hostname": "web.example.com", "ports": ["22/tcp", "80/tcp", "443/tcp"] }
},
{
"id": "tmp_bn_finding1", "boardId": "tmp_brd_topology",
"refType": "finding", "refId": "tmp_f_xss",
"x": 300, "y": 100,
"data": { "title": "Reflected XSS in search endpoint", "severity": "high", "cvssScore": 6.1 }
}
],
"boardEdges": [
{
"id": "tmp_be_1", "boardId": "tmp_brd_topology",
"source": "tmp_bn_host1", "target": "tmp_bn_finding1",
"label": "exploits"
}
],
"activity": [
{
"id": "tmp_act_1", "engagementId": "tmp_eng",
"timestamp": 0, "actor": "operator",
"kind": "engagement.create", "message": "Engagement created"
}
]
}
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Pwnote
- Source: Pwnote/skills
- 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.