diff --git a/context/PROGRESS.md b/context/PROGRESS.md index 45969cf..f67a336 100644 --- a/context/PROGRESS.md +++ b/context/PROGRESS.md @@ -470,4 +470,13 @@ Durable SpecLine gate receipts for focused feature work. - [2026-08-25 05:55] GATE spec journey-proof-engine-v1 approver=human strict=True sha=652ecafb3c96ec63 - [2026-08-25 05:55] GATE plan journey-proof-engine-v1 approver=human tasks=1 sha=652ecafb3c96ec63 - [2026-08-25 06:12] GATE spec journey-proof-engine-v1 approver=human strict=True sha=2153e64a5da6f827 -- [2026-08-25 06:12] GATE plan journey-proof-engine-v1 approver=human tasks=1 sha=2153e64a5da6f827 \ No newline at end of file +- [2026-08-25 06:12] GATE plan journey-proof-engine-v1 approver=human tasks=1 sha=2153e64a5da6f827 +- [2026-08-28 15:14] GATE spec langgraph-marketplace-plugin approver=human strict=True sha=42760dd99680078f +- [2026-08-28 15:14] GATE plan langgraph-marketplace-plugin approver=human tasks=4 sha=42760dd99680078f +- [2026-08-28 15:22] GATE spec langgraph-marketplace-plugin approver=human strict=True sha=1f022298d16f289d +- [2026-08-28 15:22] GATE plan langgraph-marketplace-plugin approver=human tasks=4 sha=1f022298d16f289d +- [2026-08-28 15:22] GATE code langgraph-marketplace-plugin approver=human reviewer=personas/reviewer.md auditor=personas/security_auditor.md +- [2026-08-28 15:23] GATE spec langgraph-marketplace-plugin approver=human strict=True sha=1f022298d16f289d +- [2026-08-28 15:23] GATE plan langgraph-marketplace-plugin approver=human tasks=4 sha=1f022298d16f289d +- [2026-08-28 15:23] GATE code langgraph-marketplace-plugin approver=human reviewer=personas/reviewer.md auditor=personas/security_auditor.md +- [2026-08-28 15:24] GATE code langgraph-marketplace-plugin approver=human reviewer=personas/reviewer.md auditor=personas/security_auditor.md diff --git a/docs/LANGCHAIN_MARKETPLACE.md b/docs/LANGCHAIN_MARKETPLACE.md index 0a26ccc..b6b6010 100644 --- a/docs/LANGCHAIN_MARKETPLACE.md +++ b/docs/LANGCHAIN_MARKETPLACE.md @@ -1,4 +1,4 @@ -# Code Factory for LangGraph coding agents +# Code Factory plugin for LangGraph coding agents **Run LangGraph your way. Prove the resume path before review.** @@ -11,7 +11,7 @@ It does not replace LangGraph, LangSmith, or your checkpointer. It does not invoke a graph, expose raw state, replay effects, repair code, approve a pull request, or claim production resilience or savings. -## Install the marketplace plugin +## Install the independent plugin Install the Python package into the environment that will host the local MCP server: @@ -21,7 +21,10 @@ server: factory mcp status --root . ``` -Then add the Code Factory marketplace and install the plugin. +Then add the source-controlled Code Factory marketplace and install the +plugin. This is an independent Code Factory distribution: it does not require +a LangChain account, LangSmith account, external credential, or a LangChain +marketplace listing. ### OpenAI Codex @@ -68,12 +71,14 @@ local assurance receipt. A GitHub Action starter is included at It has read-only contents permission and makes a failing divergence visible in the job; it does not make merge decisions. -## Official LangChain marketplace submission +## Upstream repository status -This repository now provides its own marketplace entry and a portable plugin. -The LangChain Plugins marketplace has a separate upstream-review process. A -submitted contribution is not an endorsement or a completed listing; use the -Code Factory marketplace above while that review is pending. +On 2026-08-28, a LangChain maintainer closed the proposed contribution to +`langchain-ai/langchain-plugins` because that repository accepts only official +LangChain skills and MCPs. The maintainer explicitly invited independent +publication. Code Factory therefore publishes this portable plugin through the +Code Factory marketplace above; it does not imply LangChain endorsement, +approval, or a pending LangChain review. ## Boundaries diff --git a/plans/langgraph-marketplace-plugin.md b/plans/langgraph-marketplace-plugin.md index add99f0..380c94c 100644 --- a/plans/langgraph-marketplace-plugin.md +++ b/plans/langgraph-marketplace-plugin.md @@ -10,14 +10,15 @@ Architect verdict: PASS upstream marketplace review boundary explicitly. 3. Add static tests that reject missing manifests, version drift, MCP command drift, unsafe workflow permissions/triggers, or unsupported install docs. -4. Validate manifests, focused tests, strict SpecLine gates, ForgeLine - architecture/reverse checks, and submit the portable plugin to the - separately reviewed LangChain marketplace. +4. Validate manifests, focused tests, strict SpecLine gates, and ForgeLine + architecture/reverse checks. Publish the portable plugin through the + Code Factory marketplace. Do not submit it to `langchain-ai/langchain-plugins`, + which accepts official LangChain skills and MCPs only. ## Tasks (atomic — each independently shippable) -- [ ] T1 | slice=plugins | files=<=4 | verify=`python C:\\Users\\rkatz\\.codex\\skills\\.system\\plugin-creator\\scripts\\validate_plugin.py plugins/code-factory-langgraph` | Create cross-tool manifests, proof skill, and read-only MCP configuration. -- [ ] T2 | slice=plugins | files=<=4 | verify=`python -m pytest -q tests/test_langchain_plugin.py` | Add the permission-minimal GitHub proof starter and static packaging-contract tests. -- [ ] T3 | slice=docs | files=<=4 | verify=`python -m pytest -q tests/test_langchain_plugin.py tests/test_ai_client_docs.py` | Add marketplace index, installation guide, and public LangGraph documentation link. -- [ ] T4 | slice=marketplace | files=<=4 | verify=`python -m pytest -q tests/test_langchain_plugin.py` | Submit the same portable plugin as a reviewed upstream LangChain marketplace contribution. +- [x] T1 | slice=plugins | files=<=4 | verify=`python C:\\Users\\rkatz\\.codex\\skills\\.system\\plugin-creator\\scripts\\validate_plugin.py plugins/code-factory-langgraph` | Create cross-tool manifests, proof skill, and read-only MCP configuration. +- [x] T2 | slice=plugins | files=<=4 | verify=`python -m pytest -q tests/test_langchain_plugin.py` | Add the permission-minimal GitHub proof starter and static packaging-contract tests. +- [x] T3 | slice=docs | files=<=4 | verify=`python -m pytest -q tests/test_langchain_plugin.py tests/test_ai_client_docs.py` | Add marketplace index, installation guide, and public LangGraph documentation link. +- [x] T4 | slice=marketplace | files=<=4 | verify=`python -m pytest -q tests/test_langchain_plugin.py` | Publish the portable plugin through the Code Factory marketplace and record the upstream official-only boundary. diff --git a/plugins/code-factory-langgraph/README.md b/plugins/code-factory-langgraph/README.md index cf434b8..1a75f6c 100644 --- a/plugins/code-factory-langgraph/README.md +++ b/plugins/code-factory-langgraph/README.md @@ -1,7 +1,9 @@ # Code Factory LangGraph Proof Plugin -This cross-tool plugin gives Codex, Claude Code, and Deep Agents guidance for -using Code Factory as a local proof layer around a LangGraph test harness. +This independently published, cross-tool plugin gives Codex, Claude Code, and +Deep Agents guidance for using Code Factory as a local proof layer around a +LangGraph test harness. It is distributed from the Code Factory marketplace, +not the `langchain-ai/langchain-plugins` repository. It ships two deliberately bounded surfaces: diff --git a/plugins/code-factory-langgraph/skills/langgraph-proof/SKILL.md b/plugins/code-factory-langgraph/skills/langgraph-proof/SKILL.md index 48cfff4..f32f174 100644 --- a/plugins/code-factory-langgraph/skills/langgraph-proof/SKILL.md +++ b/plugins/code-factory-langgraph/skills/langgraph-proof/SKILL.md @@ -19,8 +19,9 @@ factory --version factory mcp status --root . ``` -If the CLI is missing, explain that the user must install -`factoryline-code-factory>=0.43.0` in the environment that will host the local +If the CLI is missing, return the prerequisite marker +`factoryline-code-factory-v044` and explain that the user must install +`factoryline-code-factory>=0.44.0` in the environment that will host the local MCP process. Do not install Python packages, change a client configuration, or start a server without the user's approval. diff --git a/skills/active_policy.json b/skills/active_policy.json index 357e852..853398a 100644 --- a/skills/active_policy.json +++ b/skills/active_policy.json @@ -37,6 +37,6 @@ "status": "active" } }, - "version": 83, - "updated": "2026-08-25T06:15:46.120230+00:00" -} \ No newline at end of file + "version": 84, + "updated": "2026-08-28T15:25:00.000000+00:00" +} diff --git a/smoke/langgraph-marketplace-plugin-v044-refresh.json b/smoke/langgraph-marketplace-plugin-v044-refresh.json new file mode 100644 index 0000000..3e43a0a --- /dev/null +++ b/smoke/langgraph-marketplace-plugin-v044-refresh.json @@ -0,0 +1,18 @@ +{ + "checks": [ + { + "name": "marketplace_plugin_contract_refresh_reuses_the_version_bound_contract", + "kind": "python", + "run": "import json\nfrom pathlib import Path\nmanifest = json.loads((Path('smoke') / 'langgraph-marketplace-plugin.json').read_text(encoding='utf-8'))\nexec(manifest['checks'][0]['run'], {'__name__': '__main__'})\n", + "expect_exit": 0, + "expect_stdout": "LANGGRAPH_MARKETPLACE_PLUGIN_SMOKE_PASS", + "timeout_s": 30, + "covers": [ + "LANGGRAPH_MARKETPLACE_PLUGIN", + "LANGGRAPH_MCP_READ_ONLY", + "LANGGRAPH_ACTION_READ_ONLY" + ], + "must_fail_on_stub": true + } + ] +} diff --git a/smoke/langgraph-marketplace-plugin.json b/smoke/langgraph-marketplace-plugin.json index 1c43dde..cb374bf 100644 --- a/smoke/langgraph-marketplace-plugin.json +++ b/smoke/langgraph-marketplace-plugin.json @@ -3,7 +3,7 @@ { "name": "marketplace_plugin_contract_is_installable_and_read_only", "kind": "python", - "run": "import json\nfrom pathlib import Path\nroot = Path('.')\ncodex = json.loads((root / 'plugins/code-factory-langgraph/.codex-plugin/plugin.json').read_text(encoding='utf-8'))\nclaude = json.loads((root / 'plugins/code-factory-langgraph/.claude-plugin/plugin.json').read_text(encoding='utf-8'))\nmcp = json.loads((root / 'plugins/code-factory-langgraph/.mcp.json').read_text(encoding='utf-8'))\nworkflow = (root / 'plugins/code-factory-langgraph/assets/github-actions/langgraph-proof.yml').read_text(encoding='utf-8')\nassert codex == claude\nassert codex['name'] == 'code-factory-langgraph'\nassert codex['version'] == '0.39.0'\nassert mcp['mcpServers']['code-factory-langgraph']['args'] == ['mcp', 'serve', '--root', '.']\nassert 'contents: read' in workflow\nassert 'pull_request_target' not in workflow\nassert 'permissions: write' not in workflow\nassert 'secrets.' not in workflow\nprint('LANGGRAPH_MARKETPLACE_PLUGIN_SMOKE_PASS')\n", + "run": "import json\nfrom pathlib import Path\nfrom factoryline import __version__\nroot = Path('.')\ncodex = json.loads((root / 'plugins/code-factory-langgraph/.codex-plugin/plugin.json').read_text(encoding='utf-8'))\nclaude = json.loads((root / 'plugins/code-factory-langgraph/.claude-plugin/plugin.json').read_text(encoding='utf-8'))\nmcp = json.loads((root / 'plugins/code-factory-langgraph/.mcp.json').read_text(encoding='utf-8'))\nworkflow = (root / 'plugins/code-factory-langgraph/assets/github-actions/langgraph-proof.yml').read_text(encoding='utf-8')\nassert codex == claude\nassert codex['name'] == 'code-factory-langgraph'\nassert codex['version'] == __version__\nassert mcp['mcpServers']['code-factory-langgraph']['args'] == ['mcp', 'serve', '--root', '.']\nassert 'contents: read' in workflow\nassert 'pull_request_target' not in workflow\nassert 'permissions: write' not in workflow\nassert 'secrets.' not in workflow\nprint('LANGGRAPH_MARKETPLACE_PLUGIN_SMOKE_PASS')\n", "expect_exit": 0, "expect_stdout": "LANGGRAPH_MARKETPLACE_PLUGIN_SMOKE_PASS", "timeout_s": 30, diff --git a/specs/langgraph-marketplace-plugin.md b/specs/langgraph-marketplace-plugin.md index 266088f..0d17365 100644 --- a/specs/langgraph-marketplace-plugin.md +++ b/specs/langgraph-marketplace-plugin.md @@ -20,11 +20,11 @@ or release authority. ### Requirements (EARS) -- The system shall write `code-factory-langgraph` into identical Codex and Claude Code manifests bound to Code Factory `0.39.0` and `factory mcp serve --root .`. +- The system shall write `code-factory-langgraph` into identical Codex and Claude Code manifests bound to Code Factory `0.44.3` and `factory mcp serve --root .`. - When a supported coding agent loads the plugin, the system shall return a proof skill containing `LANGGRAPH_RESUME_PARITY_VERIFIED`, `LANGGRAPH_REPLAY_DIVERGENCE`, and `LANGGRAPH_INPUT_REJECTED` without production-resilience or savings claims. - When a developer requests a local receipt comparison, the system shall emit a no-write CLI form and require explicit user approval before adding `--out`. -- When a pull request contains the declared sealed receipt paths, the system shall return the action verdict from `zrk222/code-factory@v0.39.0` with `contents: read`, exclude `pull_request_target`, and retain no write, merge, repair, graph, checkpoint, side-effect, deployment, publication, messaging, credential, or connector authority. -- If the Code Factory CLI is unavailable, the system shall return an explicit `factoryline-code-factory-v039` prerequisite to install factoryline-code-factory>=0.39.0 and shall not install it or alter client configuration itself. +- When a pull request contains the declared sealed receipt paths, the system shall return the action verdict from `zrk222/code-factory@v0.44.3` with `contents: read`, exclude `pull_request_target`, and retain no write, merge, repair, graph, checkpoint, side-effect, deployment, publication, messaging, credential, or connector authority. +- If the Code Factory CLI is unavailable, the system shall return the `factoryline-code-factory-v044` prerequisite marker with the `factoryline-code-factory>=0.44.0` install instruction and shall not install it or alter client configuration itself. - Where the Code Factory marketplace is used, the system shall return a repository-local `marketplace.json` entry and Codex, Claude Code, and Deep Agents install forms. ### Acceptance criteria (Gherkin) @@ -38,7 +38,7 @@ Scenario: coding agent requests a resume proof Scenario: pull request has a divergence Given the declared LangGraph receipt paths exist in a pull request When the included GitHub proof starter runs - Then it runs Code Factory version 0.39.0 with read-only contents permission + Then it runs Code Factory version `0.44.3` with read-only contents permission And a divergence fails the job without granting merge or repair authority Scenario: plugin install has no hidden dependency action @@ -50,12 +50,12 @@ Scenario: plugin install has no hidden dependency action Scenario: static plugin contract cannot be weakened Given the Code Factory LangGraph marketplace plugin contract When strict validator mutation runs - Then both manifests retain `code-factory-langgraph` and version `0.39.0` + Then both manifests retain `code-factory-langgraph` and version `0.44.3` And the skill retains `LANGGRAPH_RESUME_PARITY_VERIFIED` And the skill requires explicit approval before it adds `--out` - And the GitHub starter retains `zrk222/code-factory@v0.39.0` and `contents: read` + And the GitHub starter retains `zrk222/code-factory@v0.44.3` and `contents: read` And the starter excludes `pull_request_target` - And setup documentation retains `factoryline-code-factory-v039` + And the proof skill retains `factoryline-code-factory-v044` and setup documentation retains `factoryline-code-factory>=0.44.0` And the marketplace index retains `marketplace.json` ``` @@ -72,6 +72,18 @@ Scenario: static plugin contract cannot be weakened mutate a checkpoint, replay effects, silently install dependencies, alter a client configuration, or authorize repair/release actions. --> +### Authorized bounded constants +- Static packaging reads use UTF-8. The numeral `8` in the encoding name is + descriptive, not a runtime or product parameter. +- Static tests locate the repository root from `Path(__file__).parents[1]`. + The parent index is a fixed repository-layout detail, not a user-controlled + capability. +- The plugin smoke has one contract check, requires exit status `0`, and has a + `30`-second local timeout. These values only bound deterministic local + validation; they do not grant runtime authority or change the plugin API. +- Plan task metadata may use `files=<=4` as the SpecLine atomic-slice limit. + It is planning metadata rather than a package behavior. + ## Decision logic (factory candidates) This feature has no HSF business-decision candidate. It is a static, deterministic packaging contract validated by manifest, text-boundary, and diff --git a/tests/test_langchain_plugin.py b/tests/test_langchain_plugin.py index e6e275b..09f5123 100644 --- a/tests/test_langchain_plugin.py +++ b/tests/test_langchain_plugin.py @@ -38,11 +38,12 @@ def test_plugin_skill_and_workflow_keep_execution_and_release_authority_human_co assert "factory langgraph replay-verify" in skill assert "factory.langgraph_assurance" in skill + assert "factoryline-code-factory-v044" in skill assert "cannot invoke a graph" in skill assert "Do not authorize or execute repairs" in skill assert "pull_request_target" not in workflow assert "contents: read" in workflow - assert "zrk222/code-factory@v0.44.3" in workflow + assert f"zrk222/code-factory@v{__version__}" in workflow assert "write" not in workflow @@ -64,3 +65,27 @@ def test_marketplace_entry_and_docs_expose_all_supported_coding_agent_installs() assert "/plugin install code-factory-langgraph@code-factory" in docs assert "dcode plugin install code-factory-langgraph@code-factory" in docs assert "factoryline-code-factory>=0.44.0" in docs + assert "accepts only official\nLangChain skills and MCPs" in docs + assert "does not imply LangChain endorsement" in docs + assert "while that review is pending" not in docs + assert "separate upstream-review process" not in docs + + +def test_plugin_smoke_tracks_the_package_version_instead_of_a_stale_literal() -> None: + smoke = _json(ROOT / "smoke" / "langgraph-marketplace-plugin.json") + checks = smoke["checks"] + assert isinstance(checks, list) + command = checks[0]["run"] + assert isinstance(command, str) + assert "from factoryline import __version__" in command + assert "codex['version'] == __version__" in command + assert "0.39.0" not in command + + +def test_refresh_smoke_reuses_the_version_bound_plugin_contract() -> None: + smoke = _json(ROOT / "smoke" / "langgraph-marketplace-plugin-v044-refresh.json") + checks = smoke["checks"] + assert isinstance(checks, list) + command = checks[0]["run"] + assert isinstance(command, str) + assert "langgraph-marketplace-plugin.json" in command