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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion context/PROGRESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
- [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
21 changes: 13 additions & 8 deletions docs/LANGCHAIN_MARKETPLACE.md
Original file line number Diff line number Diff line change
@@ -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.**

Expand All @@ -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:
Expand All @@ -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

Expand Down Expand Up @@ -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

Expand Down
15 changes: 8 additions & 7 deletions plans/langgraph-marketplace-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
<!-- Rules enforced by `specline tasks`: one slice each, <=4 files,
explicit verify command, no forward references. -->
- [ ] 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.
6 changes: 4 additions & 2 deletions plugins/code-factory-langgraph/README.md
Original file line number Diff line number Diff line change
@@ -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:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
6 changes: 3 additions & 3 deletions skills/active_policy.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,6 @@
"status": "active"
}
},
"version": 83,
"updated": "2026-08-25T06:15:46.120230+00:00"
}
"version": 84,
"updated": "2026-08-28T15:25:00.000000+00:00"
}
18 changes: 18 additions & 0 deletions smoke/langgraph-marketplace-plugin-v044-refresh.json
Original file line number Diff line number Diff line change
@@ -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
}
]
}
2 changes: 1 addition & 1 deletion smoke/langgraph-marketplace-plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
26 changes: 19 additions & 7 deletions specs/langgraph-marketplace-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ or release authority.

### Requirements (EARS)
<!-- Every requirement uses an EARS keyword: shall / When / While / If / Where -->
- 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)
Expand All @@ -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
Expand All @@ -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`
```

Expand All @@ -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
Expand Down
27 changes: 26 additions & 1 deletion tests/test_langchain_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand All @@ -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