This repository builds conf (confluence-sync), a Go CLI that syncs Confluence pages with local Markdown files.
- Canonical specs:
openspec/project.mdopenspec/specs/*/spec.md
- Narrative summaries:
docs/specs/prd.mddocs/specs/technical-spec.mddocs/specs/README.md
- If behavior changes, update the canonical specs first, then implement.
This project supports two primary sync workflows for agents:
The agent focus on Markdown content; the human runs conf commands.
- Agent Task: Edit
.mdfiles, runconf validateto check work. - Safety: Do not touch sync-managed frontmatter keys such as
id,version,created_by,created_at,updated_by, orupdated_at.
The agent manages the full sync cycle.
- Workflow:
pull->edit->validate->diff->push. - Tests: Always run
make test(including the E2E workflow test) before pushing significant changes toconfitself.
-
pushmust always runvalidatebefore any remote write. -
Immutable frontmatter keys:
id
-
Mutable-by-sync frontmatter keys:
versioncreated_bycreated_atupdated_byupdated_at
-
User-editable frontmatter keys:
titlestate(can bedraftorcurrent. Omitted meanscurrent. Cannot be set back todraftonce published remotely).status(Confluence "Content Status" visual lozenge, e.g., "Ready to review").labels(array of strings for Confluence page labels).
-
Space identity is stored in
.confluence-state.jsonand workspace context, not in frontmatter. -
Remote deletions are hard-deleted locally during
pull(recovery is via Git history). -
.confluence-state.jsonis local state and must stay gitignored.
- Forward conversion for
pull/diffusesgithub.com/rgonek/jira-adf-converter/converterandConvertWithContext(..., converter.ConvertOptions{SourcePath: ...}). - Reverse conversion for
validate/pushusesgithub.com/rgonek/jira-adf-converter/mdconverterandConvertWithContext(..., mdconverter.ConvertOptions{SourcePath: ...}). pull/diffrun with best-effort resolution (ErrUnresolved=> diagnostics + fallback output).validate/pushrun with strict resolution (ErrUnresolved=> conversion failure).validatemust use the same strict reverse-conversion profile and hook adapters aspush.- Hooks return mapping decisions only; sync orchestration owns downloads/uploads and file writes/deletes.
- Diagram contract:
- PlantUML is supported as a first-class
plantumlcloudConfluence extension. - Mermaid is preserved as fenced code / ADF
codeBlockcontent, not a rendered Confluence diagram macro. validateshould warn before push when Mermaid fences are present so the downgrade is explicit.
- PlantUML is supported as a first-class
- Extension/macro support contract:
- PlantUML: rendered round-trip support via the custom
plantumlcloudhandler. - Mermaid: preserved-but-not-rendered only; keep it as fenced code and expect an ADF
codeBlockon push. - Raw
adf:extensionpayloads: best-effort, low-level preservation fallback for extension nodes without a repo-specific handler; not a verified end-to-end round-trip guarantee. - Unknown Confluence macros/extensions: not a first-class supported authoring target; they may only survive through best-effort raw ADF preservation, and Confluence can still reject them on push. Validate any such workflow in a sandbox before relying on it.
- PlantUML: rendered round-trip support via the custom
pushuses an ephemeral sync branch:sync/<SpaceKey>/<UTC timestamp>.pushruns in an isolated temporary worktree.pushcaptures in-scope workspace state in hidden snapshot refs:refs/confluence-sync/snapshots/<SpaceKey>/<UTC timestamp>.pushkeeps per-file commits, then merges the sync branch on full success.pushrestores out-of-scope local workspace state exactly (staged,unstaged,untracked, deletions) after successful merge.- Successful non-no-op sync runs create annotated tags:
confluence-sync/pull/<SpaceKey>/<UTC timestamp>confluence-sync/push/<SpaceKey>/<UTC timestamp>
- No-op
pull/pushruns create no commit/merge and no sync tag. - Failed
pushruns keep sync branch and snapshot refs for CLI-guided recovery. - Push commits include structured trailers:
Confluence-Page-IDConfluence-VersionConfluence-Space-KeyConfluence-URL
validate [TARGET] must check:
- Frontmatter schema.
- Immutable key integrity.
- Link and asset resolution.
- Markdown to ADF conversion.
- Strict reverse conversion behavior aligned with
pushhook/profile settings.
Validation failures must stop push immediately.
- Commands:
init,pull,push,recover,status,clean,prune,validate,diff,relink,version,doctor,search. statusreports Markdown page drift only; attachment-only changes should be checked withgit statusorconf diff.[TARGET]parsing rule:- Ends with
.md=> file mode. - Otherwise => space mode (
SPACE_KEY).
- Ends with
conf search QUERY [flags]runs full-text search over local Markdown files.- Two pluggable backends share the
Storeinterface:--engine sqlite(default, SQLite FTS5) and--engine bleve(Bleve scorch). - Index lives in
.confluence-search-index/(gitignored, local-only). - Index is updated automatically on
pull(non-fatal) and incrementally on eachsearchinvocation. - Key flags:
--space KEY— filter to a Confluence space.--label LABEL— filter by label (repeatable).--heading TEXT— restrict to sections under matching headings.--reindex— force full rebuild.--result-detail full|standard|minimal— control payload size/detail.--created-by USER/--updated-by USER— filter by creator or last updater.--created-after DATE/--created-before DATE— bound created timestamps.--updated-after DATE/--updated-before DATE— bound updated timestamps.--list-labels/--list-spaces— facet discovery.--format text|json|auto— output format (auto: TTY→text, pipe→json).--limit N(default 20) — max results.
- Recommended agent workflow:
conf search "term" --format json | <process>for token-efficient, structured reads.
- Keep a top-level
Makefilein the repository. Makefileshould provide common local workflows (at minimum:build,test, andlint/fmt).- Keep
Makefiletargets aligned with current CLI behavior and CI usage.
-
pullandpushsupport--yesand--non-interactive. -
pullsupports--skip-missing-assets,--force(-f) for full-space refresh, and--discard-localto overwrite local changes. -
pushsupports--on-conflict=pull-merge|force|cancelfor non-interactive conflict policy. -
pushsupports--dry-runto print simulated API requests and ADF output without modifying local or remote state. -
pullprovides interactive conflict resolution (Keep Both/Remote/Local) when automatic merge fails. -
pushwith--on-conflict=pull-mergeautomatically triggerspullon version conflicts. -
--yesauto-approves safety confirmations but does not choose remote-ahead conflict strategy. -
--non-interactivemust fail fast when a required decision is missing. -
Safety confirmation is required when an operation affects more than 10 markdown files or includes delete operations.
-
Add or update tests for any changed invariant.
-
NEVER perform real tests (e.g.
conf pullorconf push) targeting real Confluence spaces within the repository root. This prevents accidental commits of synced Markdown content. -
Agent Sandbox: Use a temporary directory outside of the repository for full end-to-end integration tests with real data.
-
E2E tests must run only against explicit sandbox configuration:
CONF_E2E_DOMAINCONF_E2E_EMAILCONF_E2E_API_TOKENCONF_E2E_PRIMARY_SPACE_KEYCONF_E2E_SECONDARY_SPACE_KEY- No other environment variables should be required to run
make test-e2e - Core E2E tests should create and clean up their own scratch pages instead of mutating shared seeded content
- Capability-specific live E2E suites (for example folder-fallback coverage) must still skip when the required tenant behavior is unavailable
- Never hardcode production page IDs or space keys in test code.
-
If you must use a subdirectory for small tests, use the
workspace/ortest-output/directories (both gitignored). -
Cleanup: Always delete test content from
workspace/ortest-output/after completing a test session to keep the environment clean. -
Prioritize:
- Frontmatter/validation unit tests.
- Pull/push integration tests.
- Worktree, snapshot-ref, and tag lifecycle tests (including no-op behavior).
- Round-trip Markdown <-> ADF golden tests.
- Keep
README.md,docs/usage.md,docs/automation.md, anddocs/compatibility.mdaligned with the OpenSpec files. - Keep this file aligned with
openspec/project.mdandopenspec/specs/*/spec.md.