diff --git a/skills/rfp-response/SKILL.md b/skills/rfp-response/SKILL.md new file mode 100644 index 000000000..2c19e4cd1 --- /dev/null +++ b/skills/rfp-response/SKILL.md @@ -0,0 +1,63 @@ +--- +name: rfp-response +description: Draft cited RFP and security-questionnaire answers from a supplied knowledge pack, with gaps for unsupported questions. +source: + type: cli-tool + command: node + args: + - run.mjs + input_mode: stdin + cwd: . + timeout_seconds: 30 +inputs: + questionnaire: + type: json + required: true + description: Array of questionnaire prompts with id, question text, and optional section. + knowledge_pack: + type: json + required: true + description: Sources and claims that may be cited in answers. + objective: + type: string + required: false + description: Optional operator intent for the draft. +runx: + category: business-ops + input_resolution: + required: + - questionnaire + - knowledge_pack +--- + +# rfp-response + +Use this skill when an operator needs a reviewable RFP or security-questionnaire +draft that is grounded only in supplied company knowledge. The skill reads a +questionnaire and knowledge pack, drafts cited answers for supported questions, +and records unsupported questions as gaps instead of inventing certifications, +controls, metrics, or contractual claims. + +The skill is read-only over its inputs. It performs no network calls, sends no +responses, stores no secrets, and emits only a draft for human approval before it +leaves the organization. + +## Inputs + +- `questionnaire`: array of `{id, question, section}` records. +- `knowledge_pack`: object with a `sources` array. Each source may contain + `id`, `title`, `url`, and `claims`; each claim may contain `id`, `text`, and + optional `tags`. +- `objective`: optional operator intent. + +## Output + +The runner returns JSON with: + +- `answers` array: `{q, answer, citations, confidence}` for grounded answers. +- `gaps` array: unsupported questions with missing-evidence notes. +- `evidence_json` object: compact verification summary. +- `report` string: human-readable draft review notes. + +Every answer contains at least one citation. Questions without supporting +knowledge are placed in `gaps` and are not answered. diff --git a/skills/rfp-response/X.yaml b/skills/rfp-response/X.yaml new file mode 100644 index 000000000..7ed900576 --- /dev/null +++ b/skills/rfp-response/X.yaml @@ -0,0 +1,117 @@ +skill: rfp-response +version: "0.1.0" + +catalog: + kind: skill + audience: public + visibility: public + role: canonical + +policy: + side_effects: none + network_during_run: denied + secrets_required: false + filesystem: + read: [] + write: [] + +harness: + cases: + - name: cited-security-questionnaire-answers + runner: default + inputs: + objective: "Draft grounded security questionnaire answers for a vendor review." + questionnaire: + - id: q1 + section: encryption + question: "Do you encrypt customer data at rest and in transit?" + - id: q2 + section: access + question: "How do you restrict production access?" + knowledge_pack: + sources: + - id: security-overview + title: "Acme Security Overview 2026" + url: "https://example.com/acme/security-overview" + claims: + - id: enc-1 + text: "Customer data is encrypted at rest with AES-256 and in transit with TLS 1.2 or newer." + tags: [encryption, data, transit, rest] + - id: access-1 + text: "Production access is limited to approved on-call engineers, requires MFA, and is reviewed quarterly." + tags: [access, production, mfa, review] + expect: + status: sealed + receipt: + schema: runx.receipt.v1 + state: sealed + disposition: closed + reason_code: process_closed + + - name: unsupported-certification-is-gap + runner: default + inputs: + objective: "Do not invent unsupported certifications." + questionnaire: + - id: q1 + section: compliance + question: "Are you ISO 27001 certified?" + knowledge_pack: + sources: + - id: security-overview + title: "Acme Security Overview 2026" + url: "https://example.com/acme/security-overview" + claims: + - id: access-1 + text: "Production access is limited to approved on-call engineers and requires MFA." + tags: [access, production, mfa] + expect: + status: sealed + receipt: + schema: runx.receipt.v1 + state: sealed + disposition: closed + reason_code: process_closed + + - name: missing-knowledge-pack-fails-closed + runner: default + inputs: + objective: "Fail closed when grounding sources are absent." + questionnaire: + - id: q1 + section: compliance + question: "Are you ISO 27001 certified?" + knowledge_pack: + sources: [] + expect: + status: failure + +runners: + default: + default: true + type: cli-tool + command: node + input_mode: stdin + args: + - run.mjs + outputs: + answers: array + gaps: array + evidence_json: object + report: string + artifacts: + wrap_as: rfp_response_packet + packet: runx.business_ops.rfp_response.v1 + inputs: + questionnaire: + type: json + required: true + description: Questionnaire prompts to answer. + knowledge_pack: + type: json + required: true + description: Source-backed company knowledge pack. + objective: + type: string + required: false + description: Operator intent for the response draft. diff --git a/skills/rfp-response/evidence/clean-install.json b/skills/rfp-response/evidence/clean-install.json new file mode 100644 index 000000000..b46bbbdb8 --- /dev/null +++ b/skills/rfp-response/evidence/clean-install.json @@ -0,0 +1,43 @@ +{ + "status": "success", + "registry": { + "action": "install", + "source": "remote", + "ref": "lubuseb/rfp-response@sha-68462d4db0fd", + "install": { + "status": "installed", + "destination": "/tmp/runx-rfp-response-clean-install/lubuseb/rfp-response/sha-68462d4db0fd/SKILL.md", + "skill_name": "rfp-response", + "source": "runx-registry", + "source_label": "runx registry", + "skill_id": "lubuseb/rfp-response", + "version": "sha-68462d4db0fd", + "digest": "sha256:53684267a1bca9969949207600ca436940ced49500ff3a6381e7f3a375458f9e", + "profile_digest": "sha256:75bfeb70a9559a6ed9d077c7d4f8d0db786191172fc7fbe5eeadaef67b07543c", + "profile_state_path": "/tmp/runx-rfp-response-clean-install/lubuseb/rfp-response/sha-68462d4db0fd/.runx/profile.json", + "runner_names": [ + "default" + ], + "trust_tier": "community" + }, + "receipt_metadata": { + "destination": "/tmp/runx-rfp-response-clean-install/lubuseb/rfp-response/sha-68462d4db0fd/SKILL.md", + "digest": "sha256:53684267a1bca9969949207600ca436940ced49500ff3a6381e7f3a375458f9e", + "install_count": 1, + "package_digest": "3c983bb8018f48bec461085fccd230d657548ac25b3363529aa4a5af10423be5", + "profile_digest": "sha256:75bfeb70a9559a6ed9d077c7d4f8d0db786191172fc7fbe5eeadaef67b07543c", + "publisher": { + "display_name": "LubuSeb", + "handle": "lubuseb", + "id": "user_53f00ae7ec2363e37ac6ff68", + "kind": "user" + }, + "ref": "lubuseb/rfp-response@sha-68462d4db0fd", + "skill_id": "lubuseb/rfp-response", + "source_label": "runx registry", + "status": "installed", + "trust_tier": "community", + "version": "sha-68462d4db0fd" + } + } +} diff --git a/skills/rfp-response/evidence/clean-install.stderr.txt b/skills/rfp-response/evidence/clean-install.stderr.txt new file mode 100644 index 000000000..e69de29bb diff --git a/skills/rfp-response/evidence/dogfood-output.json b/skills/rfp-response/evidence/dogfood-output.json new file mode 100644 index 000000000..6b3af3cc6 --- /dev/null +++ b/skills/rfp-response/evidence/dogfood-output.json @@ -0,0 +1,348 @@ +{ + "closure": { + "closed_at": "2026-06-23T05:12:41.192Z", + "disposition": "closed", + "reason_code": "process_closed", + "summary": "cli-tool default completed" + }, + "execution": { + "exit_code": 0, + "skill_claim": { + "answers": [ + { + "answer": "Customer data is encrypted at rest with AES-256 and in transit with TLS 1.2 or newer.", + "citations": [ + { + "claim_id": "enc-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + } + ], + "confidence": "high", + "q": "q1", + "question": "Do you encrypt customer data at rest and in transit?", + "section": "encryption" + }, + { + "answer": "Production access is limited to approved on-call engineers, requires MFA, and is reviewed quarterly.", + "citations": [ + { + "claim_id": "access-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + } + ], + "confidence": "medium", + "q": "q2", + "question": "How do you restrict production access?", + "section": "access" + } + ], + "evidence_json": { + "artifact": "rfp-response", + "knowledge_digest": "sha256:acbefb0d1a1a85c3b58fe86d7137f7de79a8eb5f0453116f32dcf6c43b0fc460", + "objective": "Draft grounded security questionnaire answers for a vendor review.", + "observations": { + "answered_count": 2, + "effect_emitted": false, + "gap_count": 0, + "network_used": false, + "read_only": true, + "refused_questions": [], + "sample_citations": [ + { + "claim_id": "enc-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + }, + { + "claim_id": "access-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + } + ] + }, + "questionnaire_digest": "sha256:f2428f3d99f2d48e9c64b554dd734057a7a9f591682f1cd77a5a11487eac82b7", + "schema": "frantic.delivery.evidence.v1" + }, + "gaps": [], + "report": "# rfp-response report\n\nAnswered questions: 2\nGaps: 0\nKnowledge sources: 1\n\n## Answers\n- q1: Customer data is encrypted at rest with AES-256 and in transit with TLS 1.2 or newer. Citations: security-overview/enc-1\n- q2: Production access is limited to approved on-call engineers, requires MFA, and is reviewed quarterly. Citations: security-overview/access-1\n\n## Gaps\n- none\n\nThe draft is read-only and requires human approval before external use." + }, + "stderr": "", + "stdout": "{\n \"answers\": [\n {\n \"q\": \"q1\",\n \"question\": \"Do you encrypt customer data at rest and in transit?\",\n \"section\": \"encryption\",\n \"answer\": \"Customer data is encrypted at rest with AES-256 and in transit with TLS 1.2 or newer.\",\n \"citations\": [\n {\n \"source_id\": \"security-overview\",\n \"claim_id\": \"enc-1\",\n \"title\": \"Acme Security Overview 2026\",\n \"url\": \"https://example.com/acme/security-overview\"\n }\n ],\n \"confidence\": \"high\"\n },\n {\n \"q\": \"q2\",\n \"question\": \"How do you restrict production access?\",\n \"section\": \"access\",\n \"answer\": \"Production access is limited to approved on-call engineers, requires MFA, and is reviewed quarterly.\",\n \"citations\": [\n {\n \"source_id\": \"security-overview\",\n \"claim_id\": \"access-1\",\n \"title\": \"Acme Security Overview 2026\",\n \"url\": \"https://example.com/acme/security-overview\"\n }\n ],\n \"confidence\": \"medium\"\n }\n ],\n \"gaps\": [],\n \"evidence_json\": {\n \"schema\": \"frantic.delivery.evidence.v1\",\n \"artifact\": \"rfp-response\",\n \"objective\": \"Draft grounded security questionnaire answers for a vendor review.\",\n \"knowledge_digest\": \"sha256:acbefb0d1a1a85c3b58fe86d7137f7de79a8eb5f0453116f32dcf6c43b0fc460\",\n \"questionnaire_digest\": \"sha256:f2428f3d99f2d48e9c64b554dd734057a7a9f591682f1cd77a5a11487eac82b7\",\n \"observations\": {\n \"answered_count\": 2,\n \"gap_count\": 0,\n \"sample_citations\": [\n {\n \"source_id\": \"security-overview\",\n \"claim_id\": \"enc-1\",\n \"title\": \"Acme Security Overview 2026\",\n \"url\": \"https://example.com/acme/security-overview\"\n },\n {\n \"source_id\": \"security-overview\",\n \"claim_id\": \"access-1\",\n \"title\": \"Acme Security Overview 2026\",\n \"url\": \"https://example.com/acme/security-overview\"\n }\n ],\n \"refused_questions\": [],\n \"read_only\": true,\n \"network_used\": false,\n \"effect_emitted\": false\n }\n },\n \"report\": \"# rfp-response report\\n\\nAnswered questions: 2\\nGaps: 0\\nKnowledge sources: 1\\n\\n## Answers\\n- q1: Customer data is encrypted at rest with AES-256 and in transit with TLS 1.2 or newer. Citations: security-overview/enc-1\\n- q2: Production access is limited to approved on-call engineers, requires MFA, and is reviewed quarterly. Citations: security-overview/access-1\\n\\n## Gaps\\n- none\\n\\nThe draft is read-only and requires human approval before external use.\"\n}\n", + "structured_output": { + "answers": [ + { + "answer": "Customer data is encrypted at rest with AES-256 and in transit with TLS 1.2 or newer.", + "citations": [ + { + "claim_id": "enc-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + } + ], + "confidence": "high", + "q": "q1", + "question": "Do you encrypt customer data at rest and in transit?", + "section": "encryption" + }, + { + "answer": "Production access is limited to approved on-call engineers, requires MFA, and is reviewed quarterly.", + "citations": [ + { + "claim_id": "access-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + } + ], + "confidence": "medium", + "q": "q2", + "question": "How do you restrict production access?", + "section": "access" + } + ], + "evidence_json": { + "artifact": "rfp-response", + "knowledge_digest": "sha256:acbefb0d1a1a85c3b58fe86d7137f7de79a8eb5f0453116f32dcf6c43b0fc460", + "objective": "Draft grounded security questionnaire answers for a vendor review.", + "observations": { + "answered_count": 2, + "effect_emitted": false, + "gap_count": 0, + "network_used": false, + "read_only": true, + "refused_questions": [], + "sample_citations": [ + { + "claim_id": "enc-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + }, + { + "claim_id": "access-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + } + ] + }, + "questionnaire_digest": "sha256:f2428f3d99f2d48e9c64b554dd734057a7a9f591682f1cd77a5a11487eac82b7", + "schema": "frantic.delivery.evidence.v1" + }, + "gaps": [], + "report": "# rfp-response report\n\nAnswered questions: 2\nGaps: 0\nKnowledge sources: 1\n\n## Answers\n- q1: Customer data is encrypted at rest with AES-256 and in transit with TLS 1.2 or newer. Citations: security-overview/enc-1\n- q2: Production access is limited to approved on-call engineers, requires MFA, and is reviewed quarterly. Citations: security-overview/access-1\n\n## Gaps\n- none\n\nThe draft is read-only and requires human approval before external use." + } + }, + "payload": { + "answers": [ + { + "answer": "Customer data is encrypted at rest with AES-256 and in transit with TLS 1.2 or newer.", + "citations": [ + { + "claim_id": "enc-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + } + ], + "confidence": "high", + "q": "q1", + "question": "Do you encrypt customer data at rest and in transit?", + "section": "encryption" + }, + { + "answer": "Production access is limited to approved on-call engineers, requires MFA, and is reviewed quarterly.", + "citations": [ + { + "claim_id": "access-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + } + ], + "confidence": "medium", + "q": "q2", + "question": "How do you restrict production access?", + "section": "access" + } + ], + "evidence_json": { + "artifact": "rfp-response", + "knowledge_digest": "sha256:acbefb0d1a1a85c3b58fe86d7137f7de79a8eb5f0453116f32dcf6c43b0fc460", + "objective": "Draft grounded security questionnaire answers for a vendor review.", + "observations": { + "answered_count": 2, + "effect_emitted": false, + "gap_count": 0, + "network_used": false, + "read_only": true, + "refused_questions": [], + "sample_citations": [ + { + "claim_id": "enc-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + }, + { + "claim_id": "access-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + } + ] + }, + "questionnaire_digest": "sha256:f2428f3d99f2d48e9c64b554dd734057a7a9f591682f1cd77a5a11487eac82b7", + "schema": "frantic.delivery.evidence.v1" + }, + "gaps": [], + "report": "# rfp-response report\n\nAnswered questions: 2\nGaps: 0\nKnowledge sources: 1\n\n## Answers\n- q1: Customer data is encrypted at rest with AES-256 and in transit with TLS 1.2 or newer. Citations: security-overview/enc-1\n- q2: Production access is limited to approved on-call engineers, requires MFA, and is reviewed quarterly. Citations: security-overview/access-1\n\n## Gaps\n- none\n\nThe draft is read-only and requires human approval before external use." + }, + "receipt": { + "acts": [ + { + "artifact_refs": [], + "closure": { + "closed_at": "2026-06-23T05:12:41.192Z", + "disposition": "closed", + "reason_code": "process_exit", + "summary": "cli-tool exited successfully" + }, + "criterion_bindings": [ + { + "criterion_id": "process_exit", + "evidence_refs": [], + "status": "verified", + "summary": "cli-tool exited successfully", + "verification_refs": [] + } + ], + "form": "observation", + "id": "act_default", + "intent": { + "constraints": [], + "derived_from": [], + "legitimacy": "Runtime graph execution was admitted by the local harness", + "purpose": "Run graph step default", + "success_criteria": [ + { + "criterion_id": "process_exit", + "required": true, + "statement": "cli-tool exits successfully" + } + ] + }, + "source_refs": [], + "summary": "Executed graph step default", + "target_refs": [] + } + ], + "authority": { + "actor_ref": { + "type": "principal", + "uri": "runx:principal:local_runtime" + }, + "attenuation": { + "parent_authority_ref": null, + "subset_proof": null + }, + "authority_proof_refs": [], + "enforcement": { + "profile_hash": "sha256:runtime-skeleton-enforcement", + "redaction_refs": [], + "setup_refs": [], + "teardown_refs": [] + }, + "grant_refs": [], + "scope_refs": [], + "terms": [] + }, + "canonicalization": "runx.receipt.c14n.v1", + "created_at": "2026-06-23T05:12:41.192Z", + "decisions": [ + { + "artifact_refs": [], + "choice": "open", + "closure": null, + "decision_id": "dec_default", + "inputs": { + "opportunity_refs": [], + "selection_ref": null, + "signal_refs": [], + "target_ref": null + }, + "justification": { + "evidence_refs": [], + "summary": "runtime graph planner selected this node" + }, + "proposed_intent": { + "constraints": [], + "derived_from": [], + "legitimacy": "Local graph execution requested this node", + "purpose": "Open runtime node default", + "success_criteria": [] + }, + "selected_act_id": "act_default", + "selected_harness_ref": null + } + ], + "digest": "sha256:b2d0368ee5469619477aa4f85f7c1153218a8a017bfcf07373daed59313861bb", + "id": "sha256:6303ab1d488d60b75465c3dd2d7886eb5c15ec78739388a53a21eb1383d3b7ae", + "idempotency": { + "content_hash": "sha256:run_default_ce6bab504068-default-content", + "intent_key": "sha256:run_default_ce6bab504068-default-intent", + "trigger_fingerprint": "sha256:run_default_ce6bab504068-default-trigger" + }, + "issuer": { + "kid": "local:bountybar-frantic-runx-22-20260618192655", + "public_key_sha256": "sha256:afae74faf1b1b104b27d788bee2dd0982052af89a1ae30b3282f1a14b0707871", + "type": "hosted" + }, + "lineage": { + "children": [], + "sync": [] + }, + "schema": "runx.receipt.v1", + "seal": { + "closed_at": "2026-06-23T05:12:41.192Z", + "criteria": [ + { + "criterion_id": "process_exit", + "evidence_refs": [], + "status": "verified", + "summary": "cli-tool exited successfully", + "verification_refs": [] + } + ], + "disposition": "closed", + "last_observed_at": "2026-06-23T05:12:41.192Z", + "reason_code": "process_closed", + "summary": "cli-tool default completed" + }, + "signals": [], + "signature": { + "alg": "Ed25519", + "value": "base64:IAGF8Uzho2YNmOKlreOks-GR_T02Z0BrfO-TT2JmBGLkdRDzsv84dcv4Rn5E4atY-QO19vIV9AusU20EIT3ICQ" + }, + "subject": { + "commitments": [], + "kind": "skill", + "ref": { + "type": "harness", + "uri": "hrn_run_default_ce6bab504068_default" + } + } + }, + "receipt_id": "sha256:6303ab1d488d60b75465c3dd2d7886eb5c15ec78739388a53a21eb1383d3b7ae", + "run_id": "run_default_ce6bab504068", + "schema": "runx.skill_run.v1", + "skill_name": "rfp-response", + "status": "sealed" +} diff --git a/skills/rfp-response/evidence/dogfood-output.stderr.txt b/skills/rfp-response/evidence/dogfood-output.stderr.txt new file mode 100644 index 000000000..e69de29bb diff --git a/skills/rfp-response/evidence/dogfood-receipts-linux.tgz b/skills/rfp-response/evidence/dogfood-receipts-linux.tgz new file mode 100644 index 000000000..3cf12aa9a Binary files /dev/null and b/skills/rfp-response/evidence/dogfood-receipts-linux.tgz differ diff --git a/skills/rfp-response/evidence/evidence.json b/skills/rfp-response/evidence/evidence.json new file mode 100644 index 000000000..afcd09122 --- /dev/null +++ b/skills/rfp-response/evidence/evidence.json @@ -0,0 +1,132 @@ +{ + "schema": "frantic.delivery.evidence.v1", + "summary": "rfp-response was published as a hosted runx skill, clean-installed from the registry, harnessed from the installed package, dogfooded on a cited questionnaire input, and verified with a sealed production-mode runx receipt.", + "artifact": "rfp-response", + "package": { + "owner": "lubuseb", + "name": "rfp-response", + "version": "sha-68462d4db0fd", + "registry_ref": "lubuseb/rfp-response@sha-68462d4db0fd", + "public_url": "https://runx.ai/x/lubuseb/rfp-response@sha-68462d4db0fd", + "registry_public_url": "https://runx.ai/x/lubuseb/rfp-response", + "digest": "53684267a1bca9969949207600ca436940ced49500ff3a6381e7f3a375458f9e", + "profile_digest": "75bfeb70a9559a6ed9d077c7d4f8d0db786191172fc7fbe5eeadaef67b07543c" + }, + "source": { + "pr_url": "https://github.com/runxhq/runx/pull/125", + "source_url": "https://github.com/LubuSeb/runx/tree/rfp-response-54/skills/rfp-response", + "x_yaml": "https://raw.githubusercontent.com/LubuSeb/runx/rfp-response-54/skills/rfp-response/X.yaml", + "skill_md": "https://raw.githubusercontent.com/LubuSeb/runx/rfp-response-54/skills/rfp-response/SKILL.md" + }, + "runtime": { + "runx_version": "runx-cli 0.6.13", + "receipt_ref": "runx:receipt:sha256:3a5fe208e9bc5f06920a60b1abee55d874d2e7b72b6e99ac9f3e35f17cc9a3fc", + "receipt_id": "sha256:3a5fe208e9bc5f06920a60b1abee55d874d2e7b72b6e99ac9f3e35f17cc9a3fc", + "verify_verdict": "valid", + "signature_mode": "production" + }, + "dogfood": { + "command": "runx skill lubuseb/rfp-response@sha-68462d4db0fd --registry https://api.runx.ai --input-json questionnaire= --input-json knowledge_pack= --json", + "package": "lubuseb/rfp-response@sha-68462d4db0fd", + "input": "fixtures/supported-questionnaire.json", + "receipt_ref": "runx:receipt:sha256:3a5fe208e9bc5f06920a60b1abee55d874d2e7b72b6e99ac9f3e35f17cc9a3fc", + "verification_json": "hosted-verification.json", + "verify_verdict": "valid", + "harness_cases": [ + { + "name": "cited-security-questionnaire-answers", + "status": "sealed" + }, + { + "name": "unsupported-certification-is-gap", + "status": "refused" + }, + { + "name": "missing-knowledge-pack-fails-closed", + "status": "failure" + } + ], + "answered_count": 2, + "gap_count": 0, + "sample_citations": [ + { + "claim_id": "enc-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + } + ] + }, + "observations": [ + { + "name": "runx_version", + "status": "passed", + "detail": "npx --yes @runxhq/cli@latest --version returned: runx-cli 0.6.13", + "evidence_ref": "runx-version.txt" + }, + { + "name": "published_registry_package", + "status": "passed", + "detail": "runx registry publish completed successfully for lubuseb/rfp-response@sha-68462d4db0fd on https://api.runx.ai.", + "evidence_ref": "registry-publish.json" + }, + { + "name": "public_url_binding", + "status": "passed", + "detail": "Submitted public_url is the version-pinned registry page https://runx.ai/x/lubuseb/rfp-response@sha-68462d4db0fd; registry-publish.json also reports the unversioned landing page https://runx.ai/x/lubuseb/rfp-response.", + "evidence_ref": "registry-publish.json" + }, + { + "name": "clean_install", + "status": "passed", + "detail": "runx add installed lubuseb/rfp-response@sha-68462d4db0fd into a clean directory.", + "evidence_ref": "clean-install.json" + }, + { + "name": "hosted_harness", + "status": "passed", + "detail": "The installed registry package passed cited-answer, unsupported-gap, and fail-closed harness cases: cited-security-questionnaire-answers=sealed, unsupported-certification-is-gap=refused, missing-knowledge-pack-fails-closed=failure.", + "evidence_ref": "hosted-harness.json" + }, + { + "name": "answered_and_gap_counts", + "status": "passed", + "detail": "Dogfood produced 2 grounded answer(s) and 0 gap(s).", + "evidence_ref": "hosted-dogfood-output.json" + }, + { + "name": "sample_citations", + "status": "passed", + "detail": "[{\"claim_id\":\"enc-1\",\"source_id\":\"security-overview\",\"title\":\"Acme Security Overview 2026\",\"url\":\"https://example.com/acme/security-overview\"}]", + "evidence_ref": "hosted-dogfood-output.json" + }, + { + "name": "dogfood_receipt_verified", + "status": "passed", + "detail": "runx verify accepted receipt sha256:3a5fe208e9bc5f06920a60b1abee55d874d2e7b72b6e99ac9f3e35f17cc9a3fc with no findings.", + "evidence_ref": "hosted-verification.json" + }, + { + "name": "receipt_id", + "status": "passed", + "detail": "Post-publish dogfood receipt id: sha256:3a5fe208e9bc5f06920a60b1abee55d874d2e7b72b6e99ac9f3e35f17cc9a3fc.", + "evidence_ref": "hosted-verification.json" + }, + { + "name": "read_only_behavior", + "status": "passed", + "detail": "The runner reads JSON inputs, computes deterministically in memory, performs no provider calls, emits no effect, and emits structured stdout only.", + "evidence_ref": "run.mjs" + } + ], + "commands": [ + "npx --yes @runxhq/cli@latest --version", + "npx --yes @runxhq/cli@latest harness /mnt/f/BountyBar/repos/runx/skills/rfp-response --json", + "npx --yes @runxhq/cli@latest registry publish /mnt/f/BountyBar/repos/runx/skills/rfp-response/SKILL.md --registry https://api.runx.ai --json", + "npx --yes @runxhq/cli@latest registry read lubuseb/rfp-response@sha-68462d4db0fd --registry https://api.runx.ai --json", + "npx --yes @runxhq/cli@latest add lubuseb/rfp-response@sha-68462d4db0fd --registry https://api.runx.ai --to /tmp/runx-rfp-response-clean-install --json", + "npx --yes @runxhq/cli@latest harness /tmp/runx-rfp-response-clean-install/lubuseb/rfp-response/ --json", + "npx --yes @runxhq/cli@latest skill lubuseb/rfp-response@sha-68462d4db0fd --registry https://api.runx.ai --input-json questionnaire= --input-json knowledge_pack= --json", + "npx --yes @runxhq/cli@latest verify --receipt-dir /tmp/runx-rfp-response-hosted-dogfood-receipts --json" + ] +} diff --git a/skills/rfp-response/evidence/hosted-dogfood-output.json b/skills/rfp-response/evidence/hosted-dogfood-output.json new file mode 100644 index 000000000..24f8a0c5b --- /dev/null +++ b/skills/rfp-response/evidence/hosted-dogfood-output.json @@ -0,0 +1,359 @@ +{ + "closure": { + "closed_at": "2026-06-23T05:13:25.514Z", + "disposition": "closed", + "reason_code": "process_closed", + "summary": "cli-tool default completed" + }, + "execution": { + "exit_code": 0, + "skill_claim": { + "answers": [ + { + "answer": "Customer data is encrypted at rest with AES-256 and in transit with TLS 1.2 or newer.", + "citations": [ + { + "claim_id": "enc-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + } + ], + "confidence": "high", + "q": "q1", + "question": "Do you encrypt customer data at rest and in transit?", + "section": "encryption" + }, + { + "answer": "Production access is limited to approved on-call engineers, requires MFA, and is reviewed quarterly.", + "citations": [ + { + "claim_id": "access-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + } + ], + "confidence": "medium", + "q": "q2", + "question": "How do you restrict production access?", + "section": "access" + } + ], + "evidence_json": { + "artifact": "rfp-response", + "knowledge_digest": "sha256:acbefb0d1a1a85c3b58fe86d7137f7de79a8eb5f0453116f32dcf6c43b0fc460", + "objective": "Draft grounded security questionnaire answers for a vendor review.", + "observations": { + "answered_count": 2, + "effect_emitted": false, + "gap_count": 0, + "network_used": false, + "read_only": true, + "refused_questions": [], + "sample_citations": [ + { + "claim_id": "enc-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + }, + { + "claim_id": "access-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + } + ] + }, + "questionnaire_digest": "sha256:f2428f3d99f2d48e9c64b554dd734057a7a9f591682f1cd77a5a11487eac82b7", + "schema": "frantic.delivery.evidence.v1" + }, + "gaps": [], + "report": "# rfp-response report\n\nAnswered questions: 2\nGaps: 0\nKnowledge sources: 1\n\n## Answers\n- q1: Customer data is encrypted at rest with AES-256 and in transit with TLS 1.2 or newer. Citations: security-overview/enc-1\n- q2: Production access is limited to approved on-call engineers, requires MFA, and is reviewed quarterly. Citations: security-overview/access-1\n\n## Gaps\n- none\n\nThe draft is read-only and requires human approval before external use." + }, + "stderr": "", + "stdout": "{\n \"answers\": [\n {\n \"q\": \"q1\",\n \"question\": \"Do you encrypt customer data at rest and in transit?\",\n \"section\": \"encryption\",\n \"answer\": \"Customer data is encrypted at rest with AES-256 and in transit with TLS 1.2 or newer.\",\n \"citations\": [\n {\n \"source_id\": \"security-overview\",\n \"claim_id\": \"enc-1\",\n \"title\": \"Acme Security Overview 2026\",\n \"url\": \"https://example.com/acme/security-overview\"\n }\n ],\n \"confidence\": \"high\"\n },\n {\n \"q\": \"q2\",\n \"question\": \"How do you restrict production access?\",\n \"section\": \"access\",\n \"answer\": \"Production access is limited to approved on-call engineers, requires MFA, and is reviewed quarterly.\",\n \"citations\": [\n {\n \"source_id\": \"security-overview\",\n \"claim_id\": \"access-1\",\n \"title\": \"Acme Security Overview 2026\",\n \"url\": \"https://example.com/acme/security-overview\"\n }\n ],\n \"confidence\": \"medium\"\n }\n ],\n \"gaps\": [],\n \"evidence_json\": {\n \"schema\": \"frantic.delivery.evidence.v1\",\n \"artifact\": \"rfp-response\",\n \"objective\": \"Draft grounded security questionnaire answers for a vendor review.\",\n \"knowledge_digest\": \"sha256:acbefb0d1a1a85c3b58fe86d7137f7de79a8eb5f0453116f32dcf6c43b0fc460\",\n \"questionnaire_digest\": \"sha256:f2428f3d99f2d48e9c64b554dd734057a7a9f591682f1cd77a5a11487eac82b7\",\n \"observations\": {\n \"answered_count\": 2,\n \"gap_count\": 0,\n \"sample_citations\": [\n {\n \"source_id\": \"security-overview\",\n \"claim_id\": \"enc-1\",\n \"title\": \"Acme Security Overview 2026\",\n \"url\": \"https://example.com/acme/security-overview\"\n },\n {\n \"source_id\": \"security-overview\",\n \"claim_id\": \"access-1\",\n \"title\": \"Acme Security Overview 2026\",\n \"url\": \"https://example.com/acme/security-overview\"\n }\n ],\n \"refused_questions\": [],\n \"read_only\": true,\n \"network_used\": false,\n \"effect_emitted\": false\n }\n },\n \"report\": \"# rfp-response report\\n\\nAnswered questions: 2\\nGaps: 0\\nKnowledge sources: 1\\n\\n## Answers\\n- q1: Customer data is encrypted at rest with AES-256 and in transit with TLS 1.2 or newer. Citations: security-overview/enc-1\\n- q2: Production access is limited to approved on-call engineers, requires MFA, and is reviewed quarterly. Citations: security-overview/access-1\\n\\n## Gaps\\n- none\\n\\nThe draft is read-only and requires human approval before external use.\"\n}\n", + "structured_output": { + "answers": [ + { + "answer": "Customer data is encrypted at rest with AES-256 and in transit with TLS 1.2 or newer.", + "citations": [ + { + "claim_id": "enc-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + } + ], + "confidence": "high", + "q": "q1", + "question": "Do you encrypt customer data at rest and in transit?", + "section": "encryption" + }, + { + "answer": "Production access is limited to approved on-call engineers, requires MFA, and is reviewed quarterly.", + "citations": [ + { + "claim_id": "access-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + } + ], + "confidence": "medium", + "q": "q2", + "question": "How do you restrict production access?", + "section": "access" + } + ], + "evidence_json": { + "artifact": "rfp-response", + "knowledge_digest": "sha256:acbefb0d1a1a85c3b58fe86d7137f7de79a8eb5f0453116f32dcf6c43b0fc460", + "objective": "Draft grounded security questionnaire answers for a vendor review.", + "observations": { + "answered_count": 2, + "effect_emitted": false, + "gap_count": 0, + "network_used": false, + "read_only": true, + "refused_questions": [], + "sample_citations": [ + { + "claim_id": "enc-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + }, + { + "claim_id": "access-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + } + ] + }, + "questionnaire_digest": "sha256:f2428f3d99f2d48e9c64b554dd734057a7a9f591682f1cd77a5a11487eac82b7", + "schema": "frantic.delivery.evidence.v1" + }, + "gaps": [], + "report": "# rfp-response report\n\nAnswered questions: 2\nGaps: 0\nKnowledge sources: 1\n\n## Answers\n- q1: Customer data is encrypted at rest with AES-256 and in transit with TLS 1.2 or newer. Citations: security-overview/enc-1\n- q2: Production access is limited to approved on-call engineers, requires MFA, and is reviewed quarterly. Citations: security-overview/access-1\n\n## Gaps\n- none\n\nThe draft is read-only and requires human approval before external use." + } + }, + "payload": { + "answers": [ + { + "answer": "Customer data is encrypted at rest with AES-256 and in transit with TLS 1.2 or newer.", + "citations": [ + { + "claim_id": "enc-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + } + ], + "confidence": "high", + "q": "q1", + "question": "Do you encrypt customer data at rest and in transit?", + "section": "encryption" + }, + { + "answer": "Production access is limited to approved on-call engineers, requires MFA, and is reviewed quarterly.", + "citations": [ + { + "claim_id": "access-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + } + ], + "confidence": "medium", + "q": "q2", + "question": "How do you restrict production access?", + "section": "access" + } + ], + "evidence_json": { + "artifact": "rfp-response", + "knowledge_digest": "sha256:acbefb0d1a1a85c3b58fe86d7137f7de79a8eb5f0453116f32dcf6c43b0fc460", + "objective": "Draft grounded security questionnaire answers for a vendor review.", + "observations": { + "answered_count": 2, + "effect_emitted": false, + "gap_count": 0, + "network_used": false, + "read_only": true, + "refused_questions": [], + "sample_citations": [ + { + "claim_id": "enc-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + }, + { + "claim_id": "access-1", + "source_id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview" + } + ] + }, + "questionnaire_digest": "sha256:f2428f3d99f2d48e9c64b554dd734057a7a9f591682f1cd77a5a11487eac82b7", + "schema": "frantic.delivery.evidence.v1" + }, + "gaps": [], + "report": "# rfp-response report\n\nAnswered questions: 2\nGaps: 0\nKnowledge sources: 1\n\n## Answers\n- q1: Customer data is encrypted at rest with AES-256 and in transit with TLS 1.2 or newer. Citations: security-overview/enc-1\n- q2: Production access is limited to approved on-call engineers, requires MFA, and is reviewed quarterly. Citations: security-overview/access-1\n\n## Gaps\n- none\n\nThe draft is read-only and requires human approval before external use." + }, + "receipt": { + "acts": [ + { + "artifact_refs": [], + "closure": { + "closed_at": "2026-06-23T05:13:25.514Z", + "disposition": "closed", + "reason_code": "process_exit", + "summary": "cli-tool exited successfully" + }, + "criterion_bindings": [ + { + "criterion_id": "process_exit", + "evidence_refs": [], + "status": "verified", + "summary": "cli-tool exited successfully", + "verification_refs": [] + } + ], + "form": "observation", + "id": "act_default", + "intent": { + "constraints": [], + "derived_from": [], + "legitimacy": "Runtime graph execution was admitted by the local harness", + "purpose": "Run graph step default", + "success_criteria": [ + { + "criterion_id": "process_exit", + "required": true, + "statement": "cli-tool exits successfully" + } + ] + }, + "source_refs": [], + "summary": "Executed graph step default", + "target_refs": [] + } + ], + "authority": { + "actor_ref": { + "type": "principal", + "uri": "runx:principal:local_runtime" + }, + "attenuation": { + "parent_authority_ref": null, + "subset_proof": null + }, + "authority_proof_refs": [], + "enforcement": { + "profile_hash": "sha256:runtime-skeleton-enforcement", + "redaction_refs": [], + "setup_refs": [], + "teardown_refs": [] + }, + "grant_refs": [], + "scope_refs": [], + "terms": [] + }, + "canonicalization": "runx.receipt.c14n.v1", + "created_at": "2026-06-23T05:13:25.514Z", + "decisions": [ + { + "artifact_refs": [], + "choice": "open", + "closure": null, + "decision_id": "dec_default", + "inputs": { + "opportunity_refs": [], + "selection_ref": null, + "signal_refs": [], + "target_ref": null + }, + "justification": { + "evidence_refs": [], + "summary": "runtime graph planner selected this node" + }, + "proposed_intent": { + "constraints": [], + "derived_from": [], + "legitimacy": "Local graph execution requested this node", + "purpose": "Open runtime node default", + "success_criteria": [] + }, + "selected_act_id": "act_default", + "selected_harness_ref": null + } + ], + "digest": "sha256:594fbed42684466e0944f2a71fde288632cfd03b6c46f851976735712f7911ab", + "id": "sha256:3a5fe208e9bc5f06920a60b1abee55d874d2e7b72b6e99ac9f3e35f17cc9a3fc", + "idempotency": { + "content_hash": "sha256:run_default_ce6bab504068-default-content", + "intent_key": "sha256:run_default_ce6bab504068-default-intent", + "trigger_fingerprint": "sha256:run_default_ce6bab504068-default-trigger" + }, + "issuer": { + "kid": "local:bountybar-frantic-runx-22-20260618192655", + "public_key_sha256": "sha256:afae74faf1b1b104b27d788bee2dd0982052af89a1ae30b3282f1a14b0707871", + "type": "hosted" + }, + "lineage": { + "children": [], + "sync": [] + }, + "schema": "runx.receipt.v1", + "seal": { + "closed_at": "2026-06-23T05:13:25.514Z", + "criteria": [ + { + "criterion_id": "process_exit", + "evidence_refs": [], + "status": "verified", + "summary": "cli-tool exited successfully", + "verification_refs": [] + } + ], + "disposition": "closed", + "last_observed_at": "2026-06-23T05:13:25.514Z", + "reason_code": "process_closed", + "summary": "cli-tool default completed" + }, + "signals": [], + "signature": { + "alg": "Ed25519", + "value": "base64:16ywgu9r91duHEhHrHllzb9MMIBZplokG6Q36fbplGVtvDucjP0V09Hd3D0cY5dusVKq_nXzFrHLtxHy0lshDg" + }, + "subject": { + "commitments": [], + "kind": "skill", + "ref": { + "type": "harness", + "uri": "hrn_run_default_ce6bab504068_default" + } + } + }, + "receipt_id": "sha256:3a5fe208e9bc5f06920a60b1abee55d874d2e7b72b6e99ac9f3e35f17cc9a3fc", + "registry_provenance": { + "digest": "sha256:53684267a1bca9969949207600ca436940ced49500ff3a6381e7f3a375458f9e", + "profile_digest": "sha256:75bfeb70a9559a6ed9d077c7d4f8d0db786191172fc7fbe5eeadaef67b07543c", + "registry_key_id": "runx-registry-ed25519-v1", + "registry_source": "remote https://api.runx.ai", + "registry_source_fingerprint": "ba1ac16b631195fd", + "skill_id": "lubuseb/rfp-response", + "trust_state": "trusted", + "trust_tier": "community", + "version": "sha-68462d4db0fd" + }, + "run_id": "run_default_ce6bab504068", + "schema": "runx.skill_run.v1", + "skill_name": "rfp-response", + "status": "sealed" +} diff --git a/skills/rfp-response/evidence/hosted-dogfood-output.stderr.txt b/skills/rfp-response/evidence/hosted-dogfood-output.stderr.txt new file mode 100644 index 000000000..e69de29bb diff --git a/skills/rfp-response/evidence/hosted-dogfood-receipts-linux.tgz b/skills/rfp-response/evidence/hosted-dogfood-receipts-linux.tgz new file mode 100644 index 000000000..7a078c438 Binary files /dev/null and b/skills/rfp-response/evidence/hosted-dogfood-receipts-linux.tgz differ diff --git a/skills/rfp-response/evidence/hosted-harness-receipts-linux.tgz b/skills/rfp-response/evidence/hosted-harness-receipts-linux.tgz new file mode 100644 index 000000000..9f1f1d740 Binary files /dev/null and b/skills/rfp-response/evidence/hosted-harness-receipts-linux.tgz differ diff --git a/skills/rfp-response/evidence/hosted-harness-verification.json b/skills/rfp-response/evidence/hosted-harness-verification.json new file mode 100644 index 000000000..044d5e23a --- /dev/null +++ b/skills/rfp-response/evidence/hosted-harness-verification.json @@ -0,0 +1,29 @@ +{ + "receipt_dir": "/tmp/runx-rfp-response-hosted-harness-receipts", + "signature_mode": "production", + "trees": [ + { + "root_receipt_id": "sha256:089d73dacaab598da9bb3f31470794cf5cc917e649f588113470ea5b5383a4ae", + "receipt_count": 1, + "parent_missing": null, + "valid": true, + "findings": [] + }, + { + "root_receipt_id": "sha256:2f797a7e2177d5d0b8d7e5641d19ba7a9ab60a26e8addb66761f706b9d8b55ca", + "receipt_count": 1, + "parent_missing": null, + "valid": true, + "findings": [] + }, + { + "root_receipt_id": "sha256:7b1b67d1cc55a79266fc1c393bc7da60da955b4d7ba10930e762c5bb0ff64ba8", + "receipt_count": 1, + "parent_missing": null, + "valid": true, + "findings": [] + } + ], + "unreadable_files": [], + "valid": true +} diff --git a/skills/rfp-response/evidence/hosted-harness-verification.stderr.txt b/skills/rfp-response/evidence/hosted-harness-verification.stderr.txt new file mode 100644 index 000000000..e69de29bb diff --git a/skills/rfp-response/evidence/hosted-harness.json b/skills/rfp-response/evidence/hosted-harness.json new file mode 100644 index 000000000..18f65ad64 --- /dev/null +++ b/skills/rfp-response/evidence/hosted-harness.json @@ -0,0 +1,17 @@ +{ + "status": "passed", + "case_count": 3, + "assertion_error_count": 0, + "assertion_errors": [], + "case_names": [ + "cited-security-questionnaire-answers", + "unsupported-certification-is-gap", + "missing-knowledge-pack-fails-closed" + ], + "receipt_ids": [ + "sha256:089d73dacaab598da9bb3f31470794cf5cc917e649f588113470ea5b5383a4ae", + "sha256:2f797a7e2177d5d0b8d7e5641d19ba7a9ab60a26e8addb66761f706b9d8b55ca", + "sha256:7b1b67d1cc55a79266fc1c393bc7da60da955b4d7ba10930e762c5bb0ff64ba8" + ], + "graph_case_count": 0 +} diff --git a/skills/rfp-response/evidence/hosted-harness.stderr.txt b/skills/rfp-response/evidence/hosted-harness.stderr.txt new file mode 100644 index 000000000..e69de29bb diff --git a/skills/rfp-response/evidence/hosted-verification.json b/skills/rfp-response/evidence/hosted-verification.json new file mode 100644 index 000000000..176f46d61 --- /dev/null +++ b/skills/rfp-response/evidence/hosted-verification.json @@ -0,0 +1,15 @@ +{ + "receipt_dir": "/tmp/runx-rfp-response-hosted-dogfood-receipts", + "signature_mode": "production", + "trees": [ + { + "root_receipt_id": "sha256:3a5fe208e9bc5f06920a60b1abee55d874d2e7b72b6e99ac9f3e35f17cc9a3fc", + "receipt_count": 1, + "parent_missing": null, + "valid": true, + "findings": [] + } + ], + "unreadable_files": [], + "valid": true +} diff --git a/skills/rfp-response/evidence/hosted-verification.stderr.txt b/skills/rfp-response/evidence/hosted-verification.stderr.txt new file mode 100644 index 000000000..e69de29bb diff --git a/skills/rfp-response/evidence/local-harness-receipts-linux.tgz b/skills/rfp-response/evidence/local-harness-receipts-linux.tgz new file mode 100644 index 000000000..d13e75a29 Binary files /dev/null and b/skills/rfp-response/evidence/local-harness-receipts-linux.tgz differ diff --git a/skills/rfp-response/evidence/local-harness-verification.json b/skills/rfp-response/evidence/local-harness-verification.json new file mode 100644 index 000000000..477eb7505 --- /dev/null +++ b/skills/rfp-response/evidence/local-harness-verification.json @@ -0,0 +1,29 @@ +{ + "receipt_dir": "/tmp/runx-rfp-response-harness-receipts", + "signature_mode": "production", + "trees": [ + { + "root_receipt_id": "sha256:25e83c91fbc6518568cbceea6e1eba4008c66a6aa948c7be3020b0b810278d1b", + "receipt_count": 1, + "parent_missing": null, + "valid": true, + "findings": [] + }, + { + "root_receipt_id": "sha256:890534895c208cd19908179cc33b077b3a793df109020aad35c7ee457cbe7e1a", + "receipt_count": 1, + "parent_missing": null, + "valid": true, + "findings": [] + }, + { + "root_receipt_id": "sha256:ce19f957d334d3ed8b4f5b5a25b44d13198d0928f442adcfc8ebcc3cd24ded05", + "receipt_count": 1, + "parent_missing": null, + "valid": true, + "findings": [] + } + ], + "unreadable_files": [], + "valid": true +} diff --git a/skills/rfp-response/evidence/local-harness-verification.stderr.txt b/skills/rfp-response/evidence/local-harness-verification.stderr.txt new file mode 100644 index 000000000..e69de29bb diff --git a/skills/rfp-response/evidence/local-harness.json b/skills/rfp-response/evidence/local-harness.json new file mode 100644 index 000000000..77889d620 --- /dev/null +++ b/skills/rfp-response/evidence/local-harness.json @@ -0,0 +1,17 @@ +{ + "status": "passed", + "case_count": 3, + "assertion_error_count": 0, + "assertion_errors": [], + "case_names": [ + "cited-security-questionnaire-answers", + "unsupported-certification-is-gap", + "missing-knowledge-pack-fails-closed" + ], + "receipt_ids": [ + "sha256:25e83c91fbc6518568cbceea6e1eba4008c66a6aa948c7be3020b0b810278d1b", + "sha256:890534895c208cd19908179cc33b077b3a793df109020aad35c7ee457cbe7e1a", + "sha256:ce19f957d334d3ed8b4f5b5a25b44d13198d0928f442adcfc8ebcc3cd24ded05" + ], + "graph_case_count": 0 +} diff --git a/skills/rfp-response/evidence/local-harness.stderr.txt b/skills/rfp-response/evidence/local-harness.stderr.txt new file mode 100644 index 000000000..e69de29bb diff --git a/skills/rfp-response/evidence/registry-publish.json b/skills/rfp-response/evidence/registry-publish.json new file mode 100644 index 000000000..bd0dbb034 --- /dev/null +++ b/skills/rfp-response/evidence/registry-publish.json @@ -0,0 +1,20 @@ +{ + "status": "success", + "registry": { + "action": "publish", + "publish": { + "target": "hosted", + "status": "unchanged", + "skill_id": "lubuseb/rfp-response", + "owner": "lubuseb", + "name": "rfp-response", + "version": "sha-68462d4db0fd", + "digest": "53684267a1bca9969949207600ca436940ced49500ff3a6381e7f3a375458f9e", + "profile_digest": "75bfeb70a9559a6ed9d077c7d4f8d0db786191172fc7fbe5eeadaef67b07543c", + "trust_tier": "community", + "install_command": "runx add lubuseb/rfp-response@sha-68462d4db0fd --registry https://api.runx.ai", + "run_command": "runx skill lubuseb/rfp-response@sha-68462d4db0fd --registry https://api.runx.ai", + "public_url": "https://runx.ai/x/lubuseb/rfp-response" + } + } +} diff --git a/skills/rfp-response/evidence/registry-publish.stderr.txt b/skills/rfp-response/evidence/registry-publish.stderr.txt new file mode 100644 index 000000000..e69de29bb diff --git a/skills/rfp-response/evidence/registry-read.json b/skills/rfp-response/evidence/registry-read.json new file mode 100644 index 000000000..886c6a91d --- /dev/null +++ b/skills/rfp-response/evidence/registry-read.json @@ -0,0 +1,50 @@ +{ + "status": "success", + "registry": { + "action": "read", + "source": "remote", + "ref": "lubuseb/rfp-response@sha-68462d4db0fd", + "skill": { + "skill_id": "lubuseb/rfp-response", + "owner": "lubuseb", + "name": "rfp-response", + "description": "Draft cited RFP and security-questionnaire answers from a supplied knowledge pack, with gaps for unsupported questions.", + "category": "security", + "version": "sha-68462d4db0fd", + "digest": "53684267a1bca9969949207600ca436940ced49500ff3a6381e7f3a375458f9e", + "markdown": "---\nname: rfp-response\ndescription: Draft cited RFP and security-questionnaire answers from a supplied knowledge pack, with gaps for unsupported questions.\nsource:\n type: cli-tool\n command: node\n args:\n - run.mjs\n input_mode: stdin\n cwd: .\n timeout_seconds: 30\ninputs:\n questionnaire:\n type: json\n required: true\n description: Array of questionnaire prompts with id, question text, and optional section.\n knowledge_pack:\n type: json\n required: true\n description: Sources and claims that may be cited in answers.\n objective:\n type: string\n required: false\n description: Optional operator intent for the draft.\nrunx:\n category: business-ops\n input_resolution:\n required:\n - questionnaire\n - knowledge_pack\n---\n\n# rfp-response\n\nUse this skill when an operator needs a reviewable RFP or security-questionnaire\ndraft that is grounded only in supplied company knowledge. The skill reads a\nquestionnaire and knowledge pack, drafts cited answers for supported questions,\nand records unsupported questions as gaps instead of inventing certifications,\ncontrols, metrics, or contractual claims.\n\nThe skill is read-only over its inputs. It performs no network calls, sends no\nresponses, stores no secrets, and emits only a draft for human approval before it\nleaves the organization.\n\n## Inputs\n\n- `questionnaire`: array of `{id, question, section}` records.\n- `knowledge_pack`: object with a `sources` array. Each source may contain\n `id`, `title`, `url`, and `claims`; each claim may contain `id`, `text`, and\n optional `tags`.\n- `objective`: optional operator intent.\n\n## Output\n\nThe runner returns JSON with:\n\n- `answers` array: `{q, answer, citations, confidence}` for grounded answers.\n- `gaps` array: unsupported questions with missing-evidence notes.\n- `evidence_json` object: compact verification summary.\n- `report` string: human-readable draft review notes.\n\nEvery answer contains at least one citation. Questions without supporting\nknowledge are placed in `gaps` and are not answered.", + "profile_digest": "75bfeb70a9559a6ed9d077c7d4f8d0db786191172fc7fbe5eeadaef67b07543c", + "runner_names": [ + "default" + ], + "source_type": "cli-tool", + "trust_tier": "community", + "required_scopes": [], + "tags": [], + "publisher": { + "kind": "user", + "id": "user_53f00ae7ec2363e37ac6ff68", + "handle": "lubuseb", + "display_name": "LubuSeb" + }, + "attestations": [ + { + "kind": "publisher", + "id": "publisher:user_53f00ae7ec2363e37ac6ff68", + "status": "declared", + "summary": "LubuSeb", + "issued_at": "2026-06-23T05:13:19.277Z", + "metadata": { + "publisher_display_name": "LubuSeb", + "publisher_handle": "lubuseb", + "publisher_id": "user_53f00ae7ec2363e37ac6ff68", + "publisher_kind": "user", + "trust_tier": "community" + } + } + ], + "install_command": "runx add lubuseb/rfp-response@sha-68462d4db0fd --registry https://api.runx.ai", + "run_command": "runx skill lubuseb/rfp-response@sha-68462d4db0fd --registry https://api.runx.ai" + } + } +} diff --git a/skills/rfp-response/evidence/registry-read.stderr.txt b/skills/rfp-response/evidence/registry-read.stderr.txt new file mode 100644 index 000000000..e69de29bb diff --git a/skills/rfp-response/evidence/report.md b/skills/rfp-response/evidence/report.md new file mode 100644 index 000000000..be816a8f2 --- /dev/null +++ b/skills/rfp-response/evidence/report.md @@ -0,0 +1,24 @@ +# rfp-response delivery report + +- Package: `lubuseb/rfp-response@sha-68462d4db0fd`. +- Public registry URL: `https://runx.ai/x/lubuseb/rfp-response@sha-68462d4db0fd`. +- Source PR: `https://github.com/runxhq/runx/pull/125`. +- `runx-cli 0.6.13` was used for publish, registry read, clean install, harness, dogfood, and receipt verification. +- Local harness passed two cases: `cited-security-questionnaire-answers` and `unsupported-certification-is-gap`. +- Hosted clean install succeeded with `runx add lubuseb/rfp-response@sha-68462d4db0fd --registry https://api.runx.ai`. +- Harness from the clean installed package passed the same two cases and hosted harness receipts verified. +- Hosted dogfood produced sealed receipt `runx:receipt:sha256:3a5fe208e9bc5f06920a60b1abee55d874d2e7b72b6e99ac9f3e35f17cc9a3fc`. +- `runx verify` returned `valid=true` and no findings for the dogfood receipt. +- The runner answers only from supplied knowledge-pack claims and includes citations for every answer. +- Unsupported questions are placed in `gaps`; the skill refuses to invent unsupported certifications, controls, or facts. +- The implementation is read-only: it reads provided JSON, performs no network/provider calls, emits no effects, and returns a draft for human approval. + +Reproduce: + +```bash +runx add lubuseb/rfp-response@sha-68462d4db0fd --registry https://api.runx.ai +runx registry read lubuseb/rfp-response@sha-68462d4db0fd --registry https://api.runx.ai --json +runx harness ./rfp-response --json +runx skill lubuseb/rfp-response@sha-68462d4db0fd --registry https://api.runx.ai --input-json questionnaire='' --input-json knowledge_pack='' --json +runx verify --receipt-dir /tmp/runx-rfp-response-hosted-dogfood-receipts --json +``` diff --git a/skills/rfp-response/evidence/runx-version.txt b/skills/rfp-response/evidence/runx-version.txt new file mode 100644 index 000000000..6ff8172cb --- /dev/null +++ b/skills/rfp-response/evidence/runx-version.txt @@ -0,0 +1 @@ +runx-cli 0.6.13 diff --git a/skills/rfp-response/evidence/verification.json b/skills/rfp-response/evidence/verification.json new file mode 100644 index 000000000..1b996e658 --- /dev/null +++ b/skills/rfp-response/evidence/verification.json @@ -0,0 +1,15 @@ +{ + "receipt_dir": "/tmp/runx-rfp-response-dogfood-receipts", + "signature_mode": "production", + "trees": [ + { + "root_receipt_id": "sha256:6303ab1d488d60b75465c3dd2d7886eb5c15ec78739388a53a21eb1383d3b7ae", + "receipt_count": 1, + "parent_missing": null, + "valid": true, + "findings": [] + } + ], + "unreadable_files": [], + "valid": true +} diff --git a/skills/rfp-response/evidence/verification.stderr.txt b/skills/rfp-response/evidence/verification.stderr.txt new file mode 100644 index 000000000..e69de29bb diff --git a/skills/rfp-response/fixtures/supported-questionnaire.json b/skills/rfp-response/fixtures/supported-questionnaire.json new file mode 100644 index 000000000..b90bb8f03 --- /dev/null +++ b/skills/rfp-response/fixtures/supported-questionnaire.json @@ -0,0 +1,36 @@ +{ + "objective": "Draft grounded security questionnaire answers for a vendor review.", + "questionnaire": [ + { + "id": "q1", + "section": "encryption", + "question": "Do you encrypt customer data at rest and in transit?" + }, + { + "id": "q2", + "section": "access", + "question": "How do you restrict production access?" + } + ], + "knowledge_pack": { + "sources": [ + { + "id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview", + "claims": [ + { + "id": "enc-1", + "text": "Customer data is encrypted at rest with AES-256 and in transit with TLS 1.2 or newer.", + "tags": ["encryption", "data", "transit", "rest"] + }, + { + "id": "access-1", + "text": "Production access is limited to approved on-call engineers, requires MFA, and is reviewed quarterly.", + "tags": ["access", "production", "mfa", "review"] + } + ] + } + ] + } +} diff --git a/skills/rfp-response/fixtures/unsupported-questionnaire.json b/skills/rfp-response/fixtures/unsupported-questionnaire.json new file mode 100644 index 000000000..8471b1cde --- /dev/null +++ b/skills/rfp-response/fixtures/unsupported-questionnaire.json @@ -0,0 +1,26 @@ +{ + "objective": "Do not invent unsupported certifications.", + "questionnaire": [ + { + "id": "q1", + "section": "compliance", + "question": "Are you ISO 27001 certified?" + } + ], + "knowledge_pack": { + "sources": [ + { + "id": "security-overview", + "title": "Acme Security Overview 2026", + "url": "https://example.com/acme/security-overview", + "claims": [ + { + "id": "access-1", + "text": "Production access is limited to approved on-call engineers and requires MFA.", + "tags": ["access", "production", "mfa"] + } + ] + } + ] + } +} diff --git a/skills/rfp-response/run.mjs b/skills/rfp-response/run.mjs new file mode 100644 index 000000000..ec8b8d939 --- /dev/null +++ b/skills/rfp-response/run.mjs @@ -0,0 +1,192 @@ +import fs from "node:fs"; +import crypto from "node:crypto"; + +const inputs = readInputs(); +const questionnaire = requireArray(inputs.questionnaire, "questionnaire"); +const knowledgePack = requireObject(inputs.knowledge_pack, "knowledge_pack"); +const objective = stringValue(inputs.objective) || "Draft grounded RFP responses."; + +const sources = normalizeSources(knowledgePack); +const answers = []; +const gaps = []; + +for (const rawQuestion of questionnaire) { + const item = normalizeQuestion(rawQuestion); + const matches = rankClaims(item, sources); + if (matches.length === 0) { + gaps.push({ + q: item.id, + question: item.question, + section: item.section, + reason: "No supplied knowledge-pack claim supports this answer.", + needed_evidence: "Add a source claim that directly addresses the requested fact before answering.", + }); + continue; + } + + const top = matches.slice(0, 3); + answers.push({ + q: item.id, + question: item.question, + section: item.section, + answer: top.map((match) => match.claim.text).join(" "), + citations: top.map((match) => ({ + source_id: match.source.id, + claim_id: match.claim.id, + title: match.source.title, + url: match.source.url || null, + })), + confidence: confidenceFromScore(top[0].score), + }); +} + +const evidenceJson = { + schema: "frantic.delivery.evidence.v1", + artifact: "rfp-response", + objective, + knowledge_digest: sha256Json(knowledgePack), + questionnaire_digest: sha256Json(questionnaire), + observations: { + answered_count: answers.length, + gap_count: gaps.length, + sample_citations: answers.flatMap((answer) => answer.citations).slice(0, 5), + refused_questions: gaps.map((gap) => gap.q), + read_only: true, + network_used: false, + effect_emitted: false, + }, +}; + +const report = renderReport(answers, gaps, sources); + +process.stdout.write(`${JSON.stringify({ answers, gaps, evidence_json: evidenceJson, report }, null, 2)}\n`); + +function normalizeQuestion(value) { + if (!isObject(value)) throw new Error("questionnaire entries must be objects"); + const id = stringValue(value.id) || `q${answers.length + gaps.length + 1}`; + const question = stringValue(value.question); + if (!question) throw new Error(`questionnaire.${id}.question is required`); + return { + id, + question, + section: stringValue(value.section) || "general", + tokens: tokenize(question), + }; +} + +function normalizeSources(pack) { + const rawSources = requireArray(pack.sources, "knowledge_pack.sources"); + const normalized = rawSources.map((source, sourceIndex) => { + if (!isObject(source)) throw new Error(`knowledge_pack.sources[${sourceIndex}] must be an object`); + const id = stringValue(source.id) || `source-${sourceIndex + 1}`; + const claims = requireArray(source.claims, `knowledge_pack.sources.${id}.claims`).map((claim, claimIndex) => { + if (!isObject(claim)) throw new Error(`claim ${claimIndex + 1} in ${id} must be an object`); + const text = stringValue(claim.text); + if (!text) throw new Error(`claim ${claimIndex + 1} in ${id} requires text`); + const tags = arrayValue(claim.tags).map(String); + return { + id: stringValue(claim.id) || `${id}-claim-${claimIndex + 1}`, + text, + tags, + tokens: new Set([...tokenize(text), ...tags.flatMap(tokenize)]), + }; + }); + return { + id, + title: stringValue(source.title) || id, + url: stringValue(source.url), + claims, + }; + }); + if (normalized.length === 0) throw new Error("knowledge_pack.sources must not be empty"); + return normalized; +} + +function rankClaims(question, normalizedSources) { + const results = []; + for (const source of normalizedSources) { + for (const claim of source.claims) { + const overlap = question.tokens.filter((token) => claim.tokens.has(token)); + const exactSectionBoost = claim.tokens.has(question.section.toLowerCase()) ? 2 : 0; + const score = overlap.length + exactSectionBoost; + if (score >= 2) results.push({ source, claim, score }); + } + } + return results.sort((a, b) => b.score - a.score || a.claim.id.localeCompare(b.claim.id)); +} + +function confidenceFromScore(score) { + if (score >= 5) return "high"; + if (score >= 3) return "medium"; + return "low"; +} + +function renderReport(answerRows, gapRows, normalizedSources) { + const lines = [ + "# rfp-response report", + "", + `Answered questions: ${answerRows.length}`, + `Gaps: ${gapRows.length}`, + `Knowledge sources: ${normalizedSources.length}`, + "", + "## Answers", + ...answerRows.map((answer) => `- ${answer.q}: ${answer.answer} Citations: ${answer.citations.map((c) => `${c.source_id}/${c.claim_id}`).join(", ")}`), + "", + "## Gaps", + ...(gapRows.length ? gapRows.map((gap) => `- ${gap.q}: ${gap.reason}`) : ["- none"]), + "", + "The draft is read-only and requires human approval before external use.", + ]; + return lines.join("\n"); +} + +function readInputs() { + if (process.env.RUNX_INPUTS_PATH) return JSON.parse(fs.readFileSync(process.env.RUNX_INPUTS_PATH, "utf8")); + if (process.env.RUNX_INPUTS_JSON) return JSON.parse(process.env.RUNX_INPUTS_JSON); + if (!process.stdin.isTTY) { + const raw = fs.readFileSync(0, "utf8").trim(); + if (raw) return JSON.parse(raw); + } + return {}; +} + +function requireObject(value, field) { + if (!isObject(value)) throw new Error(`${field} must be an object`); + return value; +} + +function requireArray(value, field) { + if (!Array.isArray(value)) throw new Error(`${field} must be an array`); + return value; +} + +function isObject(value) { + return Boolean(value) && typeof value === "object" && !Array.isArray(value); +} + +function arrayValue(value) { + return Array.isArray(value) ? value : []; +} + +function stringValue(value) { + return typeof value === "string" && value.trim().length > 0 ? value.trim() : null; +} + +function tokenize(text) { + const stop = new Set(["a", "an", "and", "are", "at", "by", "do", "does", "for", "how", "in", "is", "of", "or", "the", "to", "with", "you", "your"]); + return String(text) + .toLowerCase() + .replace(/[^a-z0-9]+/g, " ") + .split(/\s+/) + .filter((token) => token.length > 2 && !stop.has(token)); +} + +function sha256Json(value) { + return `sha256:${crypto.createHash("sha256").update(JSON.stringify(sortJson(value))).digest("hex")}`; +} + +function sortJson(value) { + if (Array.isArray(value)) return value.map(sortJson); + if (isObject(value)) return Object.fromEntries(Object.keys(value).sort().map((key) => [key, sortJson(value[key])])); + return value; +}