# Project Map opencode-config — Docker-based AI coding assistant with persistent memory (opencode configuration). Runs in Docker via `docker-compose.yml` (dind + opencode services). Root `AGENTS.md` — orchestrator directive (chat = plan only, all via subagents) + global rules (pipeline, code style, language RU) + `## Tool Usage Policy` (таблица tools: commit/create-pr/create-issue/merge-pr/post-review/post-docs-review/pipeline-status/spec-status/memory-doctor/memory-save/memory-search/memory-list/memory-access/tunnel; raw bash заблокирован deny, при сбое tool — STOP, НЕ fallback; `memory-setup` REMOVED PR#103). Auto-loaded for project + bind-mounted globally in container — PR#31, PR#63. ## Structure ``` opencode-config/ ├── .github/ │ ├── workflows/ │ │ ├── ci.yml # Lint, test, typecheck, complexity (bootstrap + output-based skip) │ │ ├── permissions-check.yml # .opencode/scripts/check-permissions.py validator (step-level skip) │ │ └── adr-check.yml # ADR cross-reference validator (.opencode/scripts/check-adr-refs.py) │ └── dependabot.yml # pip + github-actions ecosystem updates ├── .opencode/ # Project-local opencode config (auto-discovery, zero env var) — PR#23 │ ├── agents/ │ │ ├── docs-reviewer.md # Docs validation subagent (project map + handoff + ADR, uses `commit`+`post-docs-review` tools) — PR#40, PR#46, PR#69 │ │ ├── memory-syncer.md # Distills gotchas from handoffs into opencode-memory — PR#69 │ │ └── reviewer.md # Code review subagent (verdict via `post-review` tool: APPROVE|REQUEST_CHANGES|NEEDS_DISCUSSION) — PR#46, PR#69 │ ├── commands/ │ │ ├── configure-opencode.md # /configure-opencode — edit opencode.json │ │ ├── run-pipeline.md # /run-pipeline — 7-phase PR pipeline │ │ └── spec.md # /spec — 9-phase spec generation │ ├── skills/ │ │ ├── add-skill/SKILL.md # Create new opencode skill │ │ ├── branch/SKILL.md # Branch naming conventions │ │ ├── code-standards/SKILL.md # Universal code style rules │ │ ├── configure-opencode/SKILL.md # Canonical rule: write to .opencode/ │ │ ├── get-project-map/SKILL.md # Maintain docs/project-map/ │ │ ├── issue/SKILL.md # GitHub issue creation │ │ ├── memory/SKILL.md # opencode-memory usage guide │ │ ├── run-pipeline/SKILL.md # 7-phase pipeline orchestration │ │ ├── python-development/SKILL.md # Python dev patterns │ │ ├── release/SKILL.md # Tag + GitHub Release │ │ ├── repo-init/SKILL.md # New repository bootstrap │ │ ├── tunnel/SKILL.md # Cloudflare tunnel toggle (tool `tunnel()`: 1-й вызов start, 2-й stop) — PR#63 (восстановлен, удалён в PR#42) │ │ ├── run-tests/SKILL.md # Test runner guide │ │ └── spec/SKILL.md # 9-phase spec generation │ ├── tools/ │ │ ├── _shared.ts # Shared module for GitHub tools: parseRepo(repo?), runGh(args, repo?, opts?), formatResult(r, toolName) — PR#65 │ │ ├── commit.ts # commit tool wrapper (1 arg message, validates format+staged) — PR#38 │ │ ├── create-issue.ts # create-issue tool wrapper (3 args, validates format+labels; optional repo?: string) — PR#38, PR#65 │ │ ├── create-pr.ts # create-pr tool wrapper (3 args, validates format+Closes #N; optional repo?: string) — PR#38, PR#65 │ │ ├── merge-pr.ts # merge-pr tool wrapper (orchestrator-safe gh pr merge; optional repo?: string) — PR#30, PR#65 │ │ ├── memory-access.ts # memory-access tool (bump frontmatter last_accessed/access_count, regex replace, atomic write tmp+rename) — PR#101 │ │ ├── memory-doctor.ts # memory-doctor tool (read-only diagnostics: rg, Python src.memory importability, env vars, memory dir, RAG index; markdown ✅/❌ report) — PR#101 │ │ ├── memory-list.ts # memory-list tool (pure TS, categories count .md or files in category with frontmatter) — PR#101 │ │ ├── memory-save.ts # memory-save tool (auto-setup mkdir+git init/clone+hook+7 categories, git commit, async reindex via spawn detached+unref) — PR#101 │ │ ├── memory-search.ts # memory-search tool (ripgrep keyword + Python semantic via spawnSync + scoring port + cross-category fallback) — PR#101 │ │ ├── pipeline-status.ts # pipeline-status tool wrapper │ │ ├── post-docs-review.ts # post-docs-review tool wrapper (3 args: pr_number, verdict enum, body; deterministic ## Docs Review Summary heading; optional repo?: string) — PR#46, PR#65 │ │ ├── post-review.ts # post-review tool wrapper (3 args: pr_number, verdict enum, body; deterministic ## Code Review Summary heading; optional repo?: string) — PR#46, PR#65 │ │ ├── spec-status.ts # spec-status tool wrapper │ │ └── tunnel.ts # Cloudflare tunnel toggle tool (start/stop без args) — PR#34 │ ├── scripts/ │ │ ├── check-adr-refs.py # ADR cross-reference validator (adr-check.yml) │ │ ├── check-permissions.py # Permissions validator (permissions-check.yml) │ │ ├── observability.py # OTel spans for tools │ │ ├── pipeline-status.py # 7-phase oracle (gh PR + CI polling, NEXT_ACTIONS with subagent_type+template) — PR#42, PR#67 (check_project_map guard) │ │ ├── scaffold-handoff.sh # Scaffold handoff + ADR stubs │ │ ├── spec-status.py # 9-phase spec oracle │ │ └── tunnel.sh # Cloudflare tunnel toggle bash (named mode via CLOUDFLARE_TUNNEL_TOKEN) — PR#34 │ ├── opencode.json # MCP servers, providers, permissions, agents (role-based tools) — PR#40, PR#69 (plugin block REMOVED PR#103, deprecated `new_api` provider REMOVED PR#106) │ ├── package.json # npm deps for tools/*.ts (deps: @vscode/ripgrep; devDeps: @types/node, typescript) — PR#101 │ └── .gitignore # Ignores node_modules, etc. ├── docs/ │ ├── handoff/ # PR handoffs (pr--.md) │ ├── decisions/ # ADRs (NNN-pr--.md) │ └── project-map/ # This file — structure snapshot ├── src/ # Python RAG CLI (memory) — PR#17 │ └── memory/ │ ├── __init__.py │ ├── __main__.py # Entry point for `python -m memory` │ ├── cli.py # CLI commands (prog="memory") │ ├── embedder.py # Embedding via OPENAI_BASE_URL (env-only, OpenAI-compatible); rate-limit-aware: Retry-After header parsing, retry=5, backoff max=30 — PR#83 │ ├── index.py # Indexing with chunking (MEMORY_CHUNK_SIZE/OVERLAP env); SHA256 incremental index (.rag/meta.json), atomic writes (.tmp+os.replace), versioning (model:chunk_size:overlap), fcntl.flock(LOCK_EX) — PR#83 │ └── search.py # Search with dedup by source in top-K ├── tests/ # pytest + TS/MJS test suite — PR#17 │ ├── _ts_loader.mjs # TS test loader (load/exec_stub/exec_stub_json/exec_real modes; relative import inlining via inlineShared()) — PR#38, PR#65 │ ├── test_agent_frontmatter.py # Agent frontmatter validators (no top-level doom_loop, permission.doom_loop present, steps:150) — PR#49, PR#69 │ ├── test_check_adr_refs.py # adr-check.yml validator │ ├── test_check_permissions.py # permissions-check.yml validator │ ├── test_cli.py # src/memory/cli.py │ ├── test_docker_compose.py # docker-compose.yml port exposure (0.0.0.0:4096, no 127.0.0.1) — PR#51 │ ├── test_dockerfile.py # Dockerfile npm install (opencode-ai + repomix; @mathew-cf/opencode-memory REMOVED PR#103, assertions inverted) — PR#57, PR#103 │ ├── test_commit_tool.py # .opencode/tools/commit.ts (via _ts_loader.mjs exec_stub_json) — PR#38 │ ├── test_commit_tool.ts # TS wrapper test (mjs loader) — PR#38 │ ├── test_create_issue_tool.py # .opencode/tools/create-issue.ts (via _ts_loader.mjs exec_stub_json; +repo explicit/omitted/invalid) — PR#38, PR#65 │ ├── test_create_issue_tool.ts # TS wrapper test (mjs loader; +repo cases) — PR#38, PR#65 │ ├── test_create_pr_tool.py # .opencode/tools/create-pr.ts (via _ts_loader.mjs exec_stub_json; +repo explicit/omitted/invalid) — PR#38, PR#65 │ ├── test_create_pr_tool.ts # TS wrapper test (mjs loader; +repo cases) — PR#38, PR#65 │ ├── test_embedder.py # src/memory/embedder.py (mocks OPENAI_BASE_URL) │ ├── test_embedder_live.py # Live embed tests (skip without RUN_LIVE=1) │ ├── test_index.py # src/memory/index.py (chunking + env override + .rag skip) │ ├── test_chunking.py # _chunk_text edge cases (empty, unicode, size.tools role-based access (8 tests) — PR#40, PR#69 │ ├── test_pipeline_status.py # .opencode/scripts/pipeline-status.py (REVIEW verdict branching) │ ├── test_pipeline_status_adr.py │ ├── test_pipeline_status_ci.py │ ├── test_pipeline_status_next_actions.py # NEXT_ACTIONS subagent_type+template per phase (25 tests) — PR#42 │ ├── test_pipeline_status_project_map.py # check_project_map guard (README.md mandatory, ADR-028) — PR#67 │ ├── test_pipeline_status_tool.py │ ├── test_pipeline_status_tool.ts # TS wrapper test (mjs loader) │ ├── test_post_docs_review_tool.py # .opencode/tools/post-docs-review.ts (via _ts_loader.mjs exec_stub_json; +repo cases) — PR#46, PR#65 │ ├── test_post_docs_review_tool.ts # TS wrapper test (mjs loader; +repo cases) — PR#46, PR#65 │ ├── test_post_review_tool.py # .opencode/tools/post-review.ts (via _ts_loader.mjs exec_stub_json; +repo cases) — PR#46, PR#65 │ ├── test_post_review_tool.ts # TS wrapper test (mjs loader; +repo cases) — PR#46, PR#65 │ ├── test_search.py # src/memory/search.py │ ├── test_spec_status.py # .opencode/scripts/spec-status.py │ ├── test_spec_status_tool.py │ ├── test_tunnel_tool.py # .opencode/scripts/tunnel.sh (6 pytest: start/stop/stale PID/toggle, isolated tmp copy + fake cloudflared) — PR#65 │ └── test_tunnel_tool.ts # .opencode/tools/tunnel.ts (4 TS: spawnSync wiring, success/error/cwd) — PR#65 ├── pyproject.toml # Python project (uv, ruff, pytest config) ├── uv.lock # Locked deps for Python project ├── .pre-commit-config.yaml # ruff + UV hooks ├── docker-compose.yml # 2 services (dind + opencode), opencode_network, 4 bind mounts, port 4096 on 0.0.0.0 — PR#24, PR#51 ├── Dockerfile # node:22-trixie-slim (Debian 13 trixie, glibc 2.41) + uv + gh + chromium + docker.io + opencode-ai + repomix + cloudflared (@mathew-cf/opencode-memory REMOVED PR#103) — PR#24, PR#34, PR#57, PR#71, PR#103 ├── .env.example # Placeholder-only env template (user copies to .env) — PR#24, PR#34 (TUNNEL_DOMAIN), PR#36 (OPENCODE_MEMORY_REMOTE/DIR), PR#106 (AI_PROVIDER_* removed, OPENCODE_MEMORY_REMOTE now optional) ├── app_data/ │ ├── opencode-memory/ # Persistent memory (separate git repo, gitignored) — PR#36 │ ├── workspaces/ # Agent working directory (.gitkeep) │ └── ssh/ # SSH keys, not in git (.gitkeep) ├── .editorconfig ├── .gitignore ├── .python-version ├── AGENTS.md # Orchestrator directive + global rules (bind-mounted globally) — PR#31 ├── LICENSE └── README.md ``` ## Pending (future PRs) - `.opencode/scripts/pipeline-status.py` fix `610452f` — PR#7 (config/scripts/ migration) - `.opencode/tools/` TS wrappers — PR#7 (config/tools/ migration) ## Update Protocol Updated by docs-reviewer subagent on each PR. Reflects tracked files only (`git ls-files`). Guarded by `pipeline-status.py:check_project_map` — README.md existence is mandatory.