diff --git a/.cursor-plugin/marketplace.json b/.cursor-plugin/marketplace.json index 5f31b87..85cf6ca 100644 --- a/.cursor-plugin/marketplace.json +++ b/.cursor-plugin/marketplace.json @@ -62,6 +62,11 @@ "name": "orchestrate", "source": "orchestrate", "description": "Fan large tasks out across parallel Cursor cloud agents with planners, workers, verifiers, and structured handoffs." + }, + { + "name": "orgx", + "source": "orgx", + "description": "OrgX execution control plane for Cursor with MCP, rules, skills, hooks, commands, and specialist agents." } ] } diff --git a/README.md b/README.md index 0955de3..61fb794 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Official Cursor plugins for popular developer tools, frameworks, and SaaS produc | `docs-canvas` | [Docs Canvas](docs-canvas/) | Cursor | Developer Tools | Render documentation — architecture notes, API references, runbooks, and codebase walkthroughs — as a navigable Cursor Canvas with sections, table of contents, diagrams, and cross-references. | | `cursor-sdk` | [Cursor SDK](cursor-sdk/) | Cursor | Developer Tools | Build apps, scripts, CI pipelines, and automations on top of the Cursor TypeScript SDK (@cursor/sdk) — runtime selection, auth, streaming, MCP, error handling, and ready-to-extend integration patterns. | | `orchestrate` | [Orchestrate](orchestrate/) | Cursor | Developer Tools | Fan large tasks out across parallel Cursor cloud agents with planners, workers, verifiers, and structured handoffs. | +| `orgx` | [OrgX](orgx/) | OrgX Team | Productivity | OrgX execution control plane for Cursor with MCP, rules, skills, hooks, commands, and specialist agents. | Author values match each plugin’s `plugin.json` `author.name` (Cursor lists `plugins@cursor.com` in the manifest). diff --git a/orgx/.cursor-plugin/plugin.json b/orgx/.cursor-plugin/plugin.json new file mode 100644 index 0000000..9387260 --- /dev/null +++ b/orgx/.cursor-plugin/plugin.json @@ -0,0 +1,35 @@ +{ + "name": "orgx", + "displayName": "OrgX", + "description": "OrgX execution control plane for Cursor with bootstrap, resumable workstreams, proof, decisions, Work Graph hooks, and specialist agents.", + "version": "0.1.1", + "author": { + "name": "OrgX Team", + "email": "reviewers@useorgx.com" + }, + "homepage": "https://useorgx.com", + "repository": "https://github.com/useorgx/cursor-plugin", + "license": "MIT", + "category": "productivity", + "tags": [ + "mcp", + "agent-orchestration", + "workstreams", + "proof", + "developer-tools" + ], + "keywords": [ + "orgx", + "cursor", + "mcp", + "workflow", + "agents" + ], + "logo": "assets/logo.svg", + "rules": "rules", + "skills": "skills", + "agents": "agents", + "commands": "commands", + "hooks": "hooks/hooks.json", + "mcpServers": ".mcp.json" +} diff --git a/orgx/.gitignore b/orgx/.gitignore new file mode 100644 index 0000000..df1bc30 --- /dev/null +++ b/orgx/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +artifacts/ +.DS_Store diff --git a/orgx/.mcp.json b/orgx/.mcp.json new file mode 100644 index 0000000..8d430c1 --- /dev/null +++ b/orgx/.mcp.json @@ -0,0 +1,8 @@ +{ + "mcpServers": { + "orgx": { + "type": "http", + "url": "https://mcp.useorgx.com/mcp" + } + } +} diff --git a/orgx/LICENSE b/orgx/LICENSE new file mode 100644 index 0000000..99835f3 --- /dev/null +++ b/orgx/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 OrgX + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/orgx/README.md b/orgx/README.md new file mode 100644 index 0000000..a218b6b --- /dev/null +++ b/orgx/README.md @@ -0,0 +1,44 @@ +# `@useorgx/cursor-plugin` + +OrgX plugin for Cursor. + +This repo contains the plugin artifact needed for Cursor Marketplace submission and local Cursor installs. It bundles the OrgX MCP server with Cursor-native rules, commands, hooks, skills, and specialist agents. + +## What this plugin includes + +- `.cursor-plugin/plugin.json` manifest +- `.mcp.json` pointing at the hosted OrgX MCP server +- Cursor rules for the OrgX execution loop +- Commands for starting and resuming workstreams, checking proof, and reviewing decisions +- Quiet hooks for session, tool, and subagent lifecycle events +- Passive Work Graph hook outbox for audit-first reconciliation +- Specialist agents for engineering, product, design, operations, marketing, sales, and orchestration + +## Local testing + +1. Run `npm run verify` +2. Run `npm run install:local` +3. Restart Cursor or run `Developer: Reload Window` +4. Confirm the plugin loads from `~/.cursor/plugins/local/orgx` + +## Hook behavior + +Cursor lifecycle hooks call `scripts/hooks/record-work-graph-event.mjs`. The +script writes compact, redacted JSONL events to +`~/.config/useorgx/wizard/hooks/events.jsonl` by default, or to +`ORGX_WIZARD_HOOK_OUTBOX` when set. + +These hook records are a passive backstop for later Work Graph reconciliation. +They should answer whether meaningful work happened without durable OrgX +writeback. They do not store raw prompts, raw transcripts, API keys, tokens, or +storage state. + +## Marketplace + +Cursor plugin docs: + +- `https://cursor.com/docs/plugins` +- `https://cursor.com/docs/reference/plugins` +- `https://cursor.com/marketplace/publish` + +The current repo is the product artifact that was previously missing. `orgx-mcp` is only the remote MCP server; Cursor Marketplace expects a plugin bundle repo like this one. diff --git a/orgx/agents/design.md b/orgx/agents/design.md new file mode 100644 index 0000000..9a45d8f --- /dev/null +++ b/orgx/agents/design.md @@ -0,0 +1,6 @@ +# Design + +Own interface quality, hierarchy, and interaction clarity. + +- Preserve the existing design system unless a change is intentional and scoped. +- Mobile behavior is part of the design, not an afterthought. diff --git a/orgx/agents/engineering.md b/orgx/agents/engineering.md new file mode 100644 index 0000000..9b65c49 --- /dev/null +++ b/orgx/agents/engineering.md @@ -0,0 +1,7 @@ +# Engineering + +Own implementation quality, verification, and technical execution. + +- Read code before changing it. +- Prefer minimal, reviewable diffs. +- Separate implemented from verified. diff --git a/orgx/agents/marketing.md b/orgx/agents/marketing.md new file mode 100644 index 0000000..fdd3658 --- /dev/null +++ b/orgx/agents/marketing.md @@ -0,0 +1,6 @@ +# Marketing + +Own positioning, messaging, and launch clarity. + +- Keep claims grounded in shipped capability. +- Translate technical value into crisp user-facing language. diff --git a/orgx/agents/operations.md b/orgx/agents/operations.md new file mode 100644 index 0000000..3fc9aec --- /dev/null +++ b/orgx/agents/operations.md @@ -0,0 +1,6 @@ +# Operations + +Own reliability, rollout safety, and runtime readiness. + +- Prefer reversible changes. +- Surface operational risk directly. diff --git a/orgx/agents/orchestrator.md b/orgx/agents/orchestrator.md new file mode 100644 index 0000000..7ff530a --- /dev/null +++ b/orgx/agents/orchestrator.md @@ -0,0 +1,7 @@ +# Orchestrator + +Coordinate cross-domain work in OrgX. + +- Keep execution aligned to the active initiative and workstream. +- Decide when a specialist agent should be invoked. +- Synthesize specialist outputs into one concrete next step. diff --git a/orgx/agents/product.md b/orgx/agents/product.md new file mode 100644 index 0000000..35c0ea7 --- /dev/null +++ b/orgx/agents/product.md @@ -0,0 +1,6 @@ +# Product + +Own problem framing, scope clarity, and measurable outcomes. + +- Translate work into user value and outcome language. +- Reduce ambiguity before expanding scope. diff --git a/orgx/agents/sales.md b/orgx/agents/sales.md new file mode 100644 index 0000000..475b0fd --- /dev/null +++ b/orgx/agents/sales.md @@ -0,0 +1,6 @@ +# Sales + +Own commercial framing and adoption-oriented narratives. + +- Focus on concrete differentiators. +- Avoid parity framing when the product category is different. diff --git a/orgx/assets/logo.svg b/orgx/assets/logo.svg new file mode 100644 index 0000000..4f362c2 --- /dev/null +++ b/orgx/assets/logo.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/orgx/commands/orgx-resume-workstream.md b/orgx/commands/orgx-resume-workstream.md new file mode 100644 index 0000000..f3e89ea --- /dev/null +++ b/orgx/commands/orgx-resume-workstream.md @@ -0,0 +1,7 @@ +Resume the most relevant OrgX workstream for the current repo. + +Checklist: +- Fetch bootstrap context for `source_client=cursor`. +- Use resumable workstreams and active sessions first. +- Re-state the current task, blockers, and the next concrete action. +- If proof or decisions are pending, surface them before continuing implementation. diff --git a/orgx/commands/orgx-review-pending-decisions.md b/orgx/commands/orgx-review-pending-decisions.md new file mode 100644 index 0000000..eb9fc43 --- /dev/null +++ b/orgx/commands/orgx-review-pending-decisions.md @@ -0,0 +1,7 @@ +Review OrgX decisions that still need human approval. + +Checklist: +- List the pending decisions in priority order. +- Give enough context to approve or reject safely. +- Do not auto-approve anything without explicit user confirmation. +- If a decision blocks execution, say exactly what remains blocked. diff --git a/orgx/commands/orgx-show-proof-status.md b/orgx/commands/orgx-show-proof-status.md new file mode 100644 index 0000000..fcd4445 --- /dev/null +++ b/orgx/commands/orgx-show-proof-status.md @@ -0,0 +1,7 @@ +Show OrgX proof status for the active workstream or task. + +Checklist: +- Prefer the currently active task or most recently resumed workstream. +- Summarize what proof exists and what proof is still missing. +- Distinguish implemented work from verified work. +- End with the smallest next action that closes the highest-signal proof gap. diff --git a/orgx/commands/orgx-start-workstream.md b/orgx/commands/orgx-start-workstream.md new file mode 100644 index 0000000..c0e5c06 --- /dev/null +++ b/orgx/commands/orgx-start-workstream.md @@ -0,0 +1,8 @@ +Start an OrgX workstream for the current repo. + +Checklist: +- Fetch bootstrap context for `source_client=cursor`. +- Prefer the active workspace and recommended action from OrgX. +- If a resumable workstream exists, explain why a new workstream is still justified before creating one. +- If execution credentials are missing, stop at setup guidance instead of pretending execution is available. +- End with the concrete next step, not a generic summary. diff --git a/orgx/docs/marketplace-submission.md b/orgx/docs/marketplace-submission.md new file mode 100644 index 0000000..4586db2 --- /dev/null +++ b/orgx/docs/marketplace-submission.md @@ -0,0 +1,30 @@ +# Marketplace Submission Notes + +## Product artifact + +Cursor Marketplace reviews plugins, not bare MCP servers. + +This repo is the plugin artifact that sits on top of `orgx-mcp` and bundles: + +- `.cursor-plugin/plugin.json` +- `.mcp.json` +- rules +- skills +- agents +- commands +- hooks + +## Publish flow + +1. Verify locally with `npm run verify` +2. Install locally with `npm run install:local` +3. Confirm the plugin loads in Cursor from `~/.cursor/plugins/local/cursor-plugin` +4. Submit for review at `https://cursor.com/marketplace/publish` + +## Repo-local overlay + +The plugin defaults can be overridden additively by project-specific overlays inside a target repo: + +- `.cursor/orgx/` +- `.cursor/commands/` +- `.cursor/rules/` diff --git a/orgx/hooks/hooks.json b/orgx/hooks/hooks.json new file mode 100644 index 0000000..89014e9 --- /dev/null +++ b/orgx/hooks/hooks.json @@ -0,0 +1,29 @@ +{ + "hooks": { + "sessionStart": [ + { + "command": "node ./scripts/hooks/session-start.mjs" + } + ], + "postToolUse": [ + { + "command": "node ./scripts/hooks/post-tool-use.mjs" + } + ], + "postToolUseFailure": [ + { + "command": "node ./scripts/hooks/post-tool-use-failure.mjs" + } + ], + "subagentStart": [ + { + "command": "node ./scripts/hooks/subagent-start.mjs" + } + ], + "subagentStop": [ + { + "command": "node ./scripts/hooks/subagent-stop.mjs" + } + ] + } +} diff --git a/orgx/package.json b/orgx/package.json new file mode 100644 index 0000000..5f81a83 --- /dev/null +++ b/orgx/package.json @@ -0,0 +1,33 @@ +{ + "name": "@useorgx/cursor-plugin", + "version": "0.1.1", + "description": "OrgX plugin for Cursor with MCP, rules, skills, passive Work Graph hooks, commands, and specialist agents.", + "type": "module", + "private": true, + "scripts": { + "verify": "node ./scripts/verify-plugin.mjs", + "install:local": "node ./scripts/install-local.mjs", + "check": "npm run verify" + }, + "engines": { + "node": ">=18.0.0" + }, + "keywords": [ + "cursor", + "cursor-plugin", + "orgx", + "mcp", + "agent-orchestration", + "workflow" + ], + "author": "OrgX Team ", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/useorgx/cursor-plugin.git" + }, + "homepage": "https://github.com/useorgx/cursor-plugin", + "bugs": { + "url": "https://github.com/useorgx/cursor-plugin/issues" + } +} diff --git a/orgx/rules/orgx-execution-loop.mdc b/orgx/rules/orgx-execution-loop.mdc new file mode 100644 index 0000000..ddcf10f --- /dev/null +++ b/orgx/rules/orgx-execution-loop.mdc @@ -0,0 +1,12 @@ +--- +description: OrgX-native execution loop for Cursor. +alwaysApply: true +--- + +# OrgX Execution Loop + +- Treat OrgX as the execution control plane, not as a passive notes store. +- Prefer starting from OrgX bootstrap context, resumable workstreams, and proof status before inventing new scope. +- If work is blocked by missing context or a real decision, surface it explicitly instead of guessing. +- Close the loop with proof, artifacts, and verification steps whenever work is ready for review. +- Keep repo-local overrides in `.cursor/orgx/` additive to the default OrgX bundle. diff --git a/orgx/scripts/hooks/post-tool-use-failure.mjs b/orgx/scripts/hooks/post-tool-use-failure.mjs new file mode 100644 index 0000000..0ddaeb5 --- /dev/null +++ b/orgx/scripts/hooks/post-tool-use-failure.mjs @@ -0,0 +1,16 @@ +#!/usr/bin/env node + +import { exitCodeForResult, main, readStdin } from './record-work-graph-event.mjs'; + +readStdin() + .then((stdinText) => + main({ + argv: ['--event=post_tool_use_failure', '--source_client=cursor'], + stdinText, + }) + ) + .then((result) => process.exit(exitCodeForResult(result))) + .catch((error) => { + process.stderr.write(`OrgX Cursor post-tool-use-failure hook failed: ${error.message}\n`); + process.exit(1); + }); diff --git a/orgx/scripts/hooks/post-tool-use.mjs b/orgx/scripts/hooks/post-tool-use.mjs new file mode 100644 index 0000000..ef1eb78 --- /dev/null +++ b/orgx/scripts/hooks/post-tool-use.mjs @@ -0,0 +1,13 @@ +#!/usr/bin/env node + +import { exitCodeForResult, main, readStdin } from './record-work-graph-event.mjs'; + +readStdin() + .then((stdinText) => + main({ argv: ['--event=post_tool_use', '--source_client=cursor'], stdinText }) + ) + .then((result) => process.exit(exitCodeForResult(result))) + .catch((error) => { + process.stderr.write(`OrgX Cursor post-tool-use hook failed: ${error.message}\n`); + process.exit(1); + }); diff --git a/orgx/scripts/hooks/record-work-graph-event.mjs b/orgx/scripts/hooks/record-work-graph-event.mjs new file mode 100644 index 0000000..30423ea --- /dev/null +++ b/orgx/scripts/hooks/record-work-graph-event.mjs @@ -0,0 +1,187 @@ +#!/usr/bin/env node + +import { appendFileSync, mkdirSync } from 'node:fs'; +import { homedir } from 'node:os'; +import { dirname, join } from 'node:path'; +import process from 'node:process'; +import { pathToFileURL } from 'node:url'; + +const SENSITIVE_PAYLOAD_KEYS = new Set([ + 'api_key', + 'apiKey', + 'authorization', + 'cookie', + 'password', + 'storage_state', + 'storageState', + 'token', + 'transcript_path', + 'transcriptPath', +]); + +export function parseArgs(argv) { + const args = {}; + for (const arg of argv) { + if (!arg.startsWith('--')) continue; + const [rawKey, ...rest] = arg.slice(2).split('='); + const key = rawKey.trim(); + if (!key) continue; + args[key] = rest.length > 0 ? rest.join('=') : 'true'; + } + return args; +} + +export function pickString(...values) { + for (const value of values) { + if (typeof value !== 'string') continue; + const trimmed = value.trim(); + if (trimmed) return trimmed; + } + return undefined; +} + +export async function readStdin() { + const chunks = []; + for await (const chunk of process.stdin) { + chunks.push(Buffer.from(chunk)); + } + return Buffer.concat(chunks).toString('utf8'); +} + +export function parseJsonRecord(value) { + try { + const parsed = JSON.parse(value || '{}'); + return parsed && typeof parsed === 'object' && !Array.isArray(parsed) + ? parsed + : {}; + } catch { + return {}; + } +} + +export function visiblePayloadKeys(payload) { + return Object.keys(payload) + .filter((key) => !SENSITIVE_PAYLOAD_KEYS.has(key)) + .slice(0, 40); +} + +export function buildWorkGraphHookRecord({ + args, + payload, + sourceClient, + event, + cwd = process.cwd(), + timestamp = new Date().toISOString(), +}) { + const toolName = pickString( + payload.tool_name, + payload.toolName, + payload.tool?.name, + payload.name + ); + const prompt = pickString(payload.prompt, payload.user_prompt, payload.userPrompt); + + return { + schema_version: '2026-05-07', + source: 'orgx_cursor_plugin_runtime_hook', + source_client: sourceClient, + event, + session_id: pickString( + payload.session_id, + payload.sessionId, + payload.conversation_id, + payload.conversationId, + args.session_id, + args.sessionId + ), + turn_id: pickString(payload.turn_id, payload.turnId, args.turn_id, args.turnId), + cwd: pickString( + payload.cwd, + payload.working_directory, + payload.workspace, + args.cwd, + cwd + ), + timestamp, + summary: { + tool_name: toolName, + prompt_chars: prompt ? prompt.length : undefined, + payload_keys: visiblePayloadKeys(payload), + transcript_path_present: Boolean( + pickString(payload.transcript_path, payload.transcriptPath) + ), + }, + }; +} + +export function appendWorkGraphHookRecord(record, outbox) { + try { + mkdirSync(dirname(outbox), { recursive: true, mode: 0o700 }); + appendFileSync(outbox, `${JSON.stringify(record)}\n`, { + encoding: 'utf8', + mode: 0o600, + }); + return true; + } catch { + return false; + } +} + +export function exitCodeForResult(result) { + return result?.work_graph_spooled ? 0 : 1; +} + +export async function main({ + argv = process.argv.slice(2), + env = process.env, + stdinText = '', + cwd = process.cwd(), + timestamp = new Date().toISOString(), +} = {}) { + const args = parseArgs(argv); + const payload = parseJsonRecord(stdinText); + const sourceClient = pickString(args.source_client, args['source-client'], 'cursor'); + const event = pickString( + args.event, + payload.hook_event_name, + payload.hookEventName, + payload.event, + payload.eventName, + 'unknown' + ); + const outbox = pickString( + args.outbox, + env.ORGX_WIZARD_HOOK_OUTBOX, + join(homedir(), '.config', 'useorgx', 'wizard', 'hooks', 'events.jsonl') + ); + const record = buildWorkGraphHookRecord({ + args, + payload, + sourceClient, + event, + cwd, + timestamp, + }); + + const workGraphSpooled = appendWorkGraphHookRecord(record, outbox); + + return { + ok: workGraphSpooled, + work_graph_spooled: workGraphSpooled, + }; +} + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { + readStdin() + .then((stdinText) => main({ stdinText })) + .then((result) => { + if (!result.work_graph_spooled) { + process.stderr.write('OrgX Cursor hook failed to spool Work Graph event.\n'); + } + process.exit(exitCodeForResult(result)); + }) + .catch((error) => { + process.stderr.write(`OrgX Cursor hook failed: ${error.message}\n`); + process.exit(1); + }); +} diff --git a/orgx/scripts/hooks/session-start.mjs b/orgx/scripts/hooks/session-start.mjs new file mode 100644 index 0000000..b6ba64a --- /dev/null +++ b/orgx/scripts/hooks/session-start.mjs @@ -0,0 +1,13 @@ +#!/usr/bin/env node + +import { exitCodeForResult, main, readStdin } from './record-work-graph-event.mjs'; + +readStdin() + .then((stdinText) => + main({ argv: ['--event=session_start', '--source_client=cursor'], stdinText }) + ) + .then((result) => process.exit(exitCodeForResult(result))) + .catch((error) => { + process.stderr.write(`OrgX Cursor session-start hook failed: ${error.message}\n`); + process.exit(1); + }); diff --git a/orgx/scripts/hooks/subagent-start.mjs b/orgx/scripts/hooks/subagent-start.mjs new file mode 100644 index 0000000..bacd6c0 --- /dev/null +++ b/orgx/scripts/hooks/subagent-start.mjs @@ -0,0 +1,13 @@ +#!/usr/bin/env node + +import { exitCodeForResult, main, readStdin } from './record-work-graph-event.mjs'; + +readStdin() + .then((stdinText) => + main({ argv: ['--event=subagent_start', '--source_client=cursor'], stdinText }) + ) + .then((result) => process.exit(exitCodeForResult(result))) + .catch((error) => { + process.stderr.write(`OrgX Cursor subagent-start hook failed: ${error.message}\n`); + process.exit(1); + }); diff --git a/orgx/scripts/hooks/subagent-stop.mjs b/orgx/scripts/hooks/subagent-stop.mjs new file mode 100644 index 0000000..37b2a25 --- /dev/null +++ b/orgx/scripts/hooks/subagent-stop.mjs @@ -0,0 +1,13 @@ +#!/usr/bin/env node + +import { exitCodeForResult, main, readStdin } from './record-work-graph-event.mjs'; + +readStdin() + .then((stdinText) => + main({ argv: ['--event=subagent_stop', '--source_client=cursor'], stdinText }) + ) + .then((result) => process.exit(exitCodeForResult(result))) + .catch((error) => { + process.stderr.write(`OrgX Cursor subagent-stop hook failed: ${error.message}\n`); + process.exit(1); + }); diff --git a/orgx/scripts/install-local.mjs b/orgx/scripts/install-local.mjs new file mode 100644 index 0000000..b15dcb7 --- /dev/null +++ b/orgx/scripts/install-local.mjs @@ -0,0 +1,14 @@ +import { mkdirSync, rmSync, symlinkSync } from 'node:fs'; +import { dirname, resolve } from 'node:path'; +import { homedir } from 'node:os'; +import { fileURLToPath } from 'node:url'; + +const pluginRoot = dirname(dirname(fileURLToPath(import.meta.url))); +const localPluginsDir = resolve(homedir(), '.cursor/plugins/local'); +const linkPath = resolve(localPluginsDir, 'orgx'); + +mkdirSync(localPluginsDir, { recursive: true }); +rmSync(linkPath, { force: true, recursive: true }); +symlinkSync(pluginRoot, linkPath, 'dir'); + +process.stdout.write(`Linked ${pluginRoot} -> ${linkPath}\n`); diff --git a/orgx/scripts/verify-plugin.mjs b/orgx/scripts/verify-plugin.mjs new file mode 100644 index 0000000..462d1f3 --- /dev/null +++ b/orgx/scripts/verify-plugin.mjs @@ -0,0 +1,81 @@ +import { existsSync, readFileSync } from 'node:fs'; +import { resolve } from 'node:path'; + +const requiredFiles = [ + '.cursor-plugin/plugin.json', + '.mcp.json', + 'rules/orgx-execution-loop.mdc', + 'hooks/hooks.json', + 'scripts/hooks/record-work-graph-event.mjs', + 'commands/orgx-start-workstream.md', + 'skills/orgx-execution-control-plane/SKILL.md', + 'skills/orgx-runtime-reporting/SKILL.md', + 'agents/orchestrator.md' +]; + +const missing = requiredFiles.filter((file) => !existsSync(resolve(file))); +if (missing.length) { + console.error('Missing required plugin files:'); + for (const file of missing) console.error(`- ${file}`); + process.exit(1); +} + +const manifest = JSON.parse(readFileSync(resolve('.cursor-plugin/plugin.json'), 'utf8')); +const mcp = JSON.parse(readFileSync(resolve('.mcp.json'), 'utf8')); +const hooks = JSON.parse(readFileSync(resolve('hooks/hooks.json'), 'utf8')); + +if (!manifest.name || !manifest.version) { + throw new Error('plugin.json must include at least name and version'); +} + +if (!mcp.mcpServers || !mcp.mcpServers.orgx || !mcp.mcpServers.orgx.url) { + throw new Error('.mcp.json must define the orgx MCP server'); +} + +if (!hooks.hooks || !hooks.hooks.sessionStart) { + throw new Error('hooks/hooks.json must include sessionStart hooks'); +} + +for (const [eventName, scriptName] of [ + ['sessionStart', 'session-start.mjs'], + ['postToolUse', 'post-tool-use.mjs'], + ['postToolUseFailure', 'post-tool-use-failure.mjs'], + ['subagentStart', 'subagent-start.mjs'], + ['subagentStop', 'subagent-stop.mjs'] +]) { + if (!Array.isArray(hooks.hooks[eventName]) || hooks.hooks[eventName].length === 0) { + throw new Error(`hooks/hooks.json must include ${eventName} hooks`); + } + const hasOrgxCommand = hooks.hooks[eventName].some( + (entry) => + entry && + typeof entry.command === 'string' && + entry.command.includes(`scripts/hooks/${scriptName}`) + ); + if (!hasOrgxCommand) { + throw new Error(`${eventName} must call scripts/hooks/${scriptName}`); + } +} + +const hookScript = readFileSync(resolve('scripts/hooks/record-work-graph-event.mjs'), 'utf8'); +const installScript = readFileSync(resolve('scripts/install-local.mjs'), 'utf8'); +if (!hookScript.includes('orgx_cursor_plugin_runtime_hook')) { + throw new Error('record-work-graph-event.mjs must emit orgx_cursor_plugin_runtime_hook records'); +} +if (!hookScript.includes('ORGX_WIZARD_HOOK_OUTBOX')) { + throw new Error('record-work-graph-event.mjs must support ORGX_WIZARD_HOOK_OUTBOX'); +} +if (hookScript.includes('transcript_path:')) { + throw new Error('record-work-graph-event.mjs must not persist raw transcript paths'); +} +if (!hookScript.includes('exitCodeForResult')) { + throw new Error('record-work-graph-event.mjs must expose hook failure exit handling'); +} +if (!installScript.includes("fileURLToPath(import.meta.url)")) { + throw new Error('install-local.mjs must resolve plugin root with fileURLToPath'); +} +if (!installScript.includes("resolve(localPluginsDir, 'orgx')")) { + throw new Error('install-local.mjs must install under the orgx plugin name'); +} + +console.log('Plugin manifest, MCP config, and hooks look valid.'); diff --git a/orgx/skills/orgx-execution-control-plane/SKILL.md b/orgx/skills/orgx-execution-control-plane/SKILL.md new file mode 100644 index 0000000..8e8c2d4 --- /dev/null +++ b/orgx/skills/orgx-execution-control-plane/SKILL.md @@ -0,0 +1,21 @@ +# OrgX Execution Control Plane + +Use this skill when working inside Cursor with OrgX active. + +## Goal + +Keep Cursor work anchored to OrgX workstreams, decisions, proof, and execution state instead of ad-hoc chat history. + +## Workflow + +1. Fetch or refresh bootstrap context. +2. Prefer resume over create when relevant work already exists. +3. Keep tool usage and edits tied to a specific workstream or task. +4. Surface blockers and pending decisions explicitly. +5. Close with proof, artifacts, and concrete next actions. + +## Guardrails + +- Do not invent work that is not grounded in the active OrgX context. +- Do not call work complete without verification. +- Keep repo-local `.cursor/orgx/` overlays additive to the plugin defaults. diff --git a/orgx/skills/orgx-proof-review/SKILL.md b/orgx/skills/orgx-proof-review/SKILL.md new file mode 100644 index 0000000..58924e7 --- /dev/null +++ b/orgx/skills/orgx-proof-review/SKILL.md @@ -0,0 +1,19 @@ +# OrgX Proof Review + +Use this skill when reviewing whether a task or workstream is actually done. + +## Goal + +Separate implementation from evidence. + +## Checklist + +1. Identify the active task or workstream. +2. Gather the available proof: tests, screenshots, artifacts, logs, links. +3. Mark each proof item as present, missing, or stale. +4. Report the smallest next action that moves the work to provable completion. + +## Guardrails + +- Never mark proof complete based on intent or unverified claims. +- If verification did not run, say that directly. diff --git a/orgx/skills/orgx-runtime-reporting/SKILL.md b/orgx/skills/orgx-runtime-reporting/SKILL.md new file mode 100644 index 0000000..765bd88 --- /dev/null +++ b/orgx/skills/orgx-runtime-reporting/SKILL.md @@ -0,0 +1,73 @@ +--- +name: orgx-runtime-reporting +description: Use when Cursor should report progress, artifacts, blockers, or completion state back to OrgX during a live task. +--- + +# OrgX Runtime Reporting + +Use this skill when Cursor should keep OrgX updated during execution. + +## Reporting contract + +There are two reporting paths: + +- **Active path:** call OrgX MCP tools during the work when you know the + initiative, task, decision, blocker, or artifact context. +- **Passive backstop:** Cursor lifecycle hooks record compact session events for + later Work Graph reconciliation. + +Do not treat hook presence as a substitute for intentional OrgX writes. Hooks +answer whether OrgX was used; MCP calls make the work durable in OrgX while the +session is still fresh. + +## Workflow + +1. Resolve available IDs from args, env, or the current OrgX context: +- `ORGX_INITIATIVE_ID` +- `ORGX_WORKSTREAM_ID` +- `ORGX_TASK_ID` +- `ORGX_RUN_ID` +- `ORGX_CORRELATION_ID` + +2. Emit activity at meaningful milestones: +- `intent` +- `execution` +- `handoff` +- `blocked` +- `completed` + +3. Register proof of work: +- When you produce a file, diff, document, screenshot, or report, register it as + an artifact with a concrete summary. + +4. Handle blockers structurally: +- If judgment is required, request a decision with explicit options. +- If context is missing, report the exact missing dependency. + +5. Close execution cleanly: +- When the task is complete and verified, emit completion activity and update + entity state if the task ID is available. + +6. If no OrgX IDs are available: +- Continue the work, but make the final response easy for the hook reconciler to + classify: name decisions, artifacts, blockers, next actions, and verification. +- Do not claim OrgX was updated unless an MCP tool or API call actually + succeeded. + +7. Preserve Work Graph continuity: +- When a Work Graph report is generated, include its `work_graph_fingerprint` + and `signup_hydration.hydration_key` in summaries or artifacts that are safe + to store. +- Treat the fingerprint as the durable claim key that lets OrgX hydrate + pre-signup audit value into a user's future workspace. +- Never derive the fingerprint from secrets or raw transcripts that would need + to leave the local machine. + +## Quality bar + +- Never post empty status updates. +- Messages must be evidence-based and specific. +- Include OrgX IDs whenever available. +- Use `source_client=cursor`. +- Preserve secrets: never emit tokens, cookies, API keys, or storage state into + activity, retro, hook summaries, or final reports.