diff --git a/.agents/skills/build-cogmap/scripts/v3_prep.py b/.agents/skills/build-cogmap/scripts/v3_prep.py index b78d724..b497026 100644 --- a/.agents/skills/build-cogmap/scripts/v3_prep.py +++ b/.agents/skills/build-cogmap/scripts/v3_prep.py @@ -36,7 +36,7 @@ def sha(prefix, text): MONTH_ABBR = {'jan':1,'feb':2,'mar':3,'apr':4,'may':5,'jun':6,'jul':7,'aug':8,'sep':9,'sept':9,'oct':10,'nov':11,'dec':12} def infer_year(month): return DEFAULT_YEAR def safe_date(y, m, d): - try: return datetime.date(y, m, min(d, 28)) + try: return datetime.date(y, m, d) except Exception: return None def parse_dates(text): found=[]; t=text diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..b4b8dd6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,29 @@ +name: CI + +on: + pull_request: + push: + branches: + - main + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Compile Python + run: python -m compileall -q . + + - name: Run tests + run: python -m unittest discover -s tests -v + + - name: Verify skill mirror is in sync + run: python cogmap-app/tools/sync_skill.py --check diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..cfa0768 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,26 @@ +# Changelog + +All notable changes to CogMap will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project uses semantic versioning for public releases. + +## [Unreleased] + +### Added + +- MIT license for public use and redistribution. +- Contribution guide with validation and skill-sync instructions. +- GitHub Actions CI that compiles Python, runs tests, and verifies the mirrored + agent skill is synchronized. +- Regression tests for date parsing and bundled demo refresh. + +### Fixed + +- Preserved valid 29th, 30th, and 31st day-of-month values during date parsing + instead of silently truncating them to the 28th. + +### Changed + +- Improved the public README with clearer prerequisites, demo guidance, install + paths, and release-readiness notes. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..cc3109d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,73 @@ +# Contributing to CogMap + +Thanks for helping improve CogMap. The project is a self-contained coding-agent +skill plus a deterministic Python pipeline, so most changes should keep the +agent instructions, Python scripts, demo assets, and mirrored skill copy aligned. + +## Development setup + +Requirements: + +- Python 3.10 or newer +- No required third-party packages for Markdown/text notes +- `olefile` only if you are testing `.onex` conversion: + +```bash +python -m pip install -r cogmap-app/requirements.txt +``` + +## Validation before opening a pull request + +Run these checks from the repository root: + +```bash +python -m compileall -q . +python -m unittest discover -s tests -v +python cogmap-app/tools/sync_skill.py --check +``` + +If `sync_skill.py --check` reports drift, regenerate the Codex mirror: + +```bash +python cogmap-app/tools/sync_skill.py +``` + +Then rerun the checks. + +## Skill source of truth + +The canonical skill lives at: + +```text +cogmap-app/skills/build-cogmap/ +``` + +The OpenAI Codex discovery copy lives at: + +```text +.agents/skills/build-cogmap/ +``` + +Do not edit the `.agents` copy directly. Edit the canonical skill, run +`python cogmap-app/tools/sync_skill.py`, and commit both the canonical change and +the regenerated mirror. + +## Pull request guidance + +- Keep changes focused and small enough to review. +- Add or update tests for behavior changes. +- Preserve the runtime separation between the immutable skill engine and the + user workspace (`./cogmap` by default). +- Do not commit personal notes, generated workspaces, `.onex` exports, or + generated `knowledge-base-viz.html` files outside the bundled synthetic demo. +- Prefer clear failure messages over silent fallbacks when user action is needed. + +## Demo refresh + +The bundled synthetic demo should render from a fresh workspace with: + +```bash +COGMAP_NO_OPEN=1 python cogmap-app/skills/build-cogmap/scripts/refresh.py --no-open +``` + +The automated test suite runs this path in a temporary workspace. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8f596cb --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Ryan Nadel + +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/README.md b/README.md index 0c38dd2..1340df4 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ # CogMap -CogMap is a tool for navigating the tsunami of information that agents and people -produce. As agents generate more content, we need new tools for thought that help -us understand what a knowledge base contains, how ideas relate, what changed, what -matters, what conflicts, what is missing, and where attention should go next. +CogMap is an agent-assisted tool for navigating the tsunami of information that +agents and people produce. As agents generate more content, we need new tools for +thought that help us understand what a knowledge base contains, how ideas relate, +what changed, what matters, what conflicts, what is missing, and where attention +should go next. CogMap treats a knowledge base not as a folder of documents, but as an evolving external memory system with time as a key organizing construct. It extracts @@ -15,6 +16,13 @@ The goal is to make accumulated knowledge navigable for both people and agents: map the concepts, trace relationships across sources, surface conflicts and gaps, notice drift or convergence, and decide where to focus next. +## Status + +CogMap is currently an early public-beta project. The bundled demo renders from a +fresh checkout, and the Markdown/text pipeline has automated smoke coverage. The +semantic extraction, resolution, and synthesis stages are intentionally performed +by your coding agent rather than by a hosted API. + ## Why Minard? Charles Joseph Minard's 1869 map of Napoleon's Russian campaign is one of the @@ -50,6 +58,18 @@ evolving landscape of thought. - Ships with a GitHub Copilot / Claude Code skill for agent-assisted refreshes. - Outputs a portable HTML artifact with embedded data and no server requirement. +## See it in action + +A synthetic demo corpus ships inside the skill. On first run, CogMap seeds a +project-local `cogmap/` workspace from that demo and renders: + +```text +cogmap/output/knowledge-base-viz.html +``` + +The generated page is fully local: no server, database, or API key is required. +Replace the demo notes with your own Markdown or text files when you are ready. + ## How CogMap uses agents CogMap is built as a deterministic pipeline with agent-powered semantic stages. @@ -65,10 +85,17 @@ while the pipeline remains the durable system of record. ## Quick start -CogMap is designed to run **inside a coding agent** such as GitHub Copilot, -Claude Code, or Codex. The Python pipeline is the engine the agent drives; the -normal user workflow is to install/open the project in your agent and ask it to -refresh or rebuild the knowledge base. +CogMap is a **coding-agent skill**, not a standalone SaaS app. The Python +pipeline is the engine the agent drives; the normal user workflow is to +install/open the project in your agent and ask it to refresh or rebuild the +knowledge base. + +### Prerequisites + +- Python 3.10 or newer. +- One of: GitHub Copilot CLI, Claude Code, or OpenAI Codex CLI. +- No LLM API key. The host coding agent performs the semantic stages. +- Optional: `olefile` for best-effort OneNote `.onex` conversion. 1. Clone or open this repository in your coding agent workspace. 2. Install or expose the skill at `cogmap-app/skills/build-cogmap`. @@ -85,6 +112,34 @@ pipeline, gives the coding agent structured actions to perform, and then resumes That agent-in-the-loop loop is what lets CogMap rebuild without requiring a separate LLM API key. +## Installation paths + +### GitHub Copilot CLI + +Copy the self-contained skill folder into your Copilot skills directory: + +```bash +cp -r cogmap-app/skills/build-cogmap ~/.copilot/skills/ +``` + +On Windows, copy `cogmap-app\skills\build-cogmap` to +`%USERPROFILE%\.copilot\skills\`. + +### Claude Code + +This repository is a Claude Code marketplace. In Claude Code: + +```text +/plugin marketplace add ryannadel/CogMap +/plugin install cogmap-knowledge-base@cogmap +``` + +### OpenAI Codex CLI + +Codex discovers agent skills under `.agents/skills`. This repository ships a +mirrored copy at `.agents/skills/build-cogmap/`, kept in sync with the canonical +skill under `cogmap-app/skills/build-cogmap/`. + ## Repository layout ```text @@ -99,3 +154,19 @@ cogmap/ Project-local workspace created at runtime ``` See `cogmap-app/README.md` for the full app guide. + +## Development + +Run the public-release checks from the repository root: + +```bash +python -m compileall -q . +python -m unittest discover -s tests -v +python cogmap-app/tools/sync_skill.py --check +``` + +See `CONTRIBUTING.md` for contribution and skill-sync guidance. + +## License + +CogMap is released under the MIT License. See `LICENSE`. diff --git a/cogmap-app/README.md b/cogmap-app/README.md index c2680ec..142aea3 100644 --- a/cogmap-app/README.md +++ b/cogmap-app/README.md @@ -68,6 +68,13 @@ cogmap/ the workspace (created in your working dir) Relocate the workspace with `COGMAP_APP` (or the finer `COGMAP_SOURCES` / `COGMAP_WORK` / `COGMAP_OUTPUT`; legacy `OSLER_*` names still accepted). +## Prerequisites + +- Python 3.10 or newer. +- GitHub Copilot CLI, Claude Code, or OpenAI Codex CLI. +- No separate LLM API key. The host coding agent performs the semantic stages. +- Optional: `olefile` for `.onex` conversion. + ## Quick start (run it with a coding agent) CogMap is a **coding agent skill**, not a standalone app you run by hand: @@ -101,10 +108,10 @@ higher-reasoning passes handle concept resolution and synthesis. Copy the self-contained skill folder into your Copilot skills directory: ```bash -cp -r skills/build-cogmap ~/.copilot/skills/ +cp -r cogmap-app/skills/build-cogmap ~/.copilot/skills/ ``` -(On Windows: copy `skills\build-cogmap` to `%USERPROFILE%\.copilot\skills\`.) +(On Windows: copy `cogmap-app\skills\build-cogmap` to `%USERPROFILE%\.copilot\skills\`.) Then say *"build the knowledge base"*. ## Install as a Claude Code plugin @@ -113,7 +120,7 @@ This repo is a Claude Code marketplace (`.claude-plugin/marketplace.json` at the repo root) exposing the `cogmap-app` plugin. In Claude Code: ``` -/plugin marketplace add /CogMap +/plugin marketplace add ryannadel/CogMap /plugin install cogmap-knowledge-base@cogmap ``` diff --git a/cogmap-app/skills/build-cogmap/scripts/v3_prep.py b/cogmap-app/skills/build-cogmap/scripts/v3_prep.py index b78d724..b497026 100644 --- a/cogmap-app/skills/build-cogmap/scripts/v3_prep.py +++ b/cogmap-app/skills/build-cogmap/scripts/v3_prep.py @@ -36,7 +36,7 @@ def sha(prefix, text): MONTH_ABBR = {'jan':1,'feb':2,'mar':3,'apr':4,'may':5,'jun':6,'jul':7,'aug':8,'sep':9,'sept':9,'oct':10,'nov':11,'dec':12} def infer_year(month): return DEFAULT_YEAR def safe_date(y, m, d): - try: return datetime.date(y, m, min(d, 28)) + try: return datetime.date(y, m, d) except Exception: return None def parse_dates(text): found=[]; t=text diff --git a/tests/test_cogmap_pipeline.py b/tests/test_cogmap_pipeline.py new file mode 100644 index 0000000..65c8ade --- /dev/null +++ b/tests/test_cogmap_pipeline.py @@ -0,0 +1,79 @@ +import json +import os +import subprocess +import sys +import tempfile +import unittest +from pathlib import Path + + +REPO_ROOT = Path(__file__).resolve().parents[1] +SKILL_DIR = REPO_ROOT / "cogmap-app" / "skills" / "build-cogmap" +SCRIPTS_DIR = SKILL_DIR / "scripts" + + +def run_script(script, workspace, cwd=None, *args): + env = dict(os.environ) + if workspace is not None: + env["COGMAP_APP"] = str(workspace) + env["COGMAP_NO_OPEN"] = "1" + env["PYTHONIOENCODING"] = "utf-8" + return subprocess.run( + [sys.executable, str(SCRIPTS_DIR / script), *args], + cwd=str(cwd or REPO_ROOT), + env=env, + capture_output=True, + text=True, + encoding="utf-8", + ) + + +class CogMapPipelineTests(unittest.TestCase): + def test_date_parsing_preserves_valid_month_days(self): + with tempfile.TemporaryDirectory() as td: + workspace = Path(td) / "cogmap" + sources = workspace / "sources" + sources.mkdir(parents=True) + (sources / "dated-notes.txt").write_text( + "On January 31, 2025 the team made a concrete decision about " + "the platform roadmap and recorded several follow-up questions. " + "On 2025-12-31 there was another substantial roadmap update. " + "The February 29, 2024 leap-day note remains valid. " + "April 31, 2025 is intentionally invalid and should be ignored.", + encoding="utf-8", + ) + + result = run_script("v3_prep.py", workspace) + + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + master = json.loads((workspace / "work" / "v3_chunks_master.json").read_text(encoding="utf-8")) + self.assertEqual(len(master["chunks"]), 1) + dates = set(master["chunks"][0]["dates"]) + self.assertIn("2025-01-31", dates) + self.assertIn("2025-12-31", dates) + self.assertIn("2024-02-29", dates) + self.assertNotIn("2025-01-28", dates) + self.assertNotIn("2025-12-28", dates) + self.assertNotIn("2025-04-30", dates) + self.assertNotIn("2025-04-31", dates) + + def test_demo_refresh_renders_html(self): + with tempfile.TemporaryDirectory() as td: + workspace = Path(td) / "cogmap" + + result = run_script("refresh.py", None, Path(td), "--no-open") + + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + self.assertIn("DONE.", result.stdout) + html = workspace / "output" / "knowledge-base-viz.html" + data_path = workspace / "output" / "knowledge-base-viz-data.json" + self.assertTrue(html.exists(), result.stdout) + self.assertTrue(data_path.exists(), result.stdout) + data = json.loads(data_path.read_text(encoding="utf-8")) + self.assertGreater(data["metadata"]["counts"]["sources"], 0) + self.assertGreater(data["metadata"]["counts"]["chunks"], 0) + self.assertIn("CogMap", html.read_text(encoding="utf-8")) + + +if __name__ == "__main__": + unittest.main()