From d6728ff3869843589637b70df5087acb8d105c89 Mon Sep 17 00:00:00 2001 From: codegeist Date: Fri, 2 Oct 2026 20:13:34 +0000 Subject: [PATCH] feat(go): bootstrap project and task lifecycle Add the minimal greenfield Go module and namespaced Taskfile commands. Require accepted work to use a linked GitHub Issue, deterministic task branch, checked squash PR, dual-host main synchronization, and cleanup. Include the refreshed shared devcontainer release gitlink. --- .devcontainer | 2 +- .oc_local/opencode.json | 1 + .../rules/codegeist-task-specification.md | 4 + .oc_local/rules/github-task-lifecycle.md | 215 ++++++++++++++++++ Taskfile.yml | 8 +- app/codegeist/go/README.md | 12 + app/codegeist/go/Taskfile.yml | 22 ++ app/codegeist/go/go.mod | 3 + app/codegeist/go/main.go | 3 + docs/developer/architecture/architecture.md | 13 +- docs/tasks/README.md | 23 +- ...go-project-and-automated-task-lifecycle.md | 87 +++++++ 12 files changed, 381 insertions(+), 12 deletions(-) create mode 100644 .oc_local/rules/github-task-lifecycle.md create mode 100644 app/codegeist/go/README.md create mode 100644 app/codegeist/go/Taskfile.yml create mode 100644 app/codegeist/go/go.mod create mode 100644 app/codegeist/go/main.go create mode 100644 docs/tasks/T014_bootstrap-go-project-and-automated-task-lifecycle.md diff --git a/.devcontainer b/.devcontainer index 0987951..a0145f2 160000 --- a/.devcontainer +++ b/.devcontainer @@ -1 +1 @@ -Subproject commit 0987951c0252e1ebd5bbf9b3ef7a68dfcbe4e54e +Subproject commit a0145f29a115c187381c7f9d3dc32289204140a8 diff --git a/.oc_local/opencode.json b/.oc_local/opencode.json index 4df4579..49b06fa 100644 --- a/.oc_local/opencode.json +++ b/.oc_local/opencode.json @@ -5,6 +5,7 @@ ".oc_local/rules/codegeist-documentation.md", ".oc_local/rules/codegeist-release.md", ".oc_local/rules/codegeist-task-specification.md", + ".oc_local/rules/github-task-lifecycle.md", ".oc_local/rules/java-coding.md", ".oc_local/rules/third-party-analysis-workflow.md", "docs/tests/README.md" diff --git a/.oc_local/rules/codegeist-task-specification.md b/.oc_local/rules/codegeist-task-specification.md index 8de5049..f8e3f71 100644 --- a/.oc_local/rules/codegeist-task-specification.md +++ b/.oc_local/rules/codegeist-task-specification.md @@ -10,6 +10,10 @@ Use the shared `/task` workflow from `.opencode`: This overlay adds only Codegeist-specific guidance. Keep generic task behavior in `.opencode/rules/task-workflow.md`. +Apply `.oc_local/rules/github-task-lifecycle.md` as the mandatory Issue, branch, +PR, merge, synchronization, and cleanup overlay for every `/task` and `/save` +invocation in this repository. + ## Codegeist Guidance - The new product direction is a greenfield Go project in `app/codegeist/go/`, diff --git a/.oc_local/rules/github-task-lifecycle.md b/.oc_local/rules/github-task-lifecycle.md new file mode 100644 index 0000000..6467588 --- /dev/null +++ b/.oc_local/rules/github-task-lifecycle.md @@ -0,0 +1,215 @@ +# GitHub Task Lifecycle + +Use this rule for every Codegeist `/task` and `/save` invocation. It is the +repository-specific mandatory overlay for the shared task and save workflows. + +## Purpose + +Every accepted Codegeist task must be traceable through one GitHub Issue, one +task branch, and one merged pull request. GitHub is the review and merge target; +the Gitea `origin` remains a synchronized source remote. The local task file +remains the source of truth for scope, acceptance criteria, status, and +verification. + +## Fixed Repository Contract + +- GitHub repository: `https://github.com/codegeist-ai/codegeist`. +- Base branch: `main`. +- Gitea source remote: `origin`. +- `docs/tasks/README.md` must retain the exact declaration + `GitHub Mirror: https://github.com/codegeist-ai/codegeist`. +- Use `GH_TOKEN` as the only GitHub credential. Before every GitHub mutation, + require it to be non-empty and validate it with a read-only `gh api user` + request using `GH_HOST=github.com` and `GH_PROMPT_DISABLED=1`. +- For GitHub HTTPS fetches and pushes, use `gh auth git-credential` as a + command-scoped credential helper backed by `GH_TOKEN`; do not persist GitHub + credentials or reconfigure the user's global helper. +- Use the already configured non-interactive credentials for Gitea. Never print, + inspect, or persist either host's token. +- Never weaken or bypass GitHub branch protection as part of this lifecycle. + +## Authorization And Precedence + +- In this repository, public tracking is mandatory rather than optional. This + rule replaces the shared optional-activation and per-Issue preview gates for + `/task spec`, `/task impl`, and `/task cancel`. +- Direct invocation of `/task spec`, `/task impl`, or `/task cancel` authorizes + the Issue and branch mutations explicitly assigned to that action below. +- Direct invocation of `/task impl` authorizes its implementation commit, branch + pushes, Issue completion, pull-request creation, check wait, squash merge, + synchronization, and branch cleanup when verification succeeds. +- Direct invocation of `/save` authorizes deterministic task-branch creation for + an already resolved task and the same publication lifecycle. When no unique + task exists, `/save` must obtain one focused approval before creating a + retrospective task and its mandatory Issue; that approval also authorizes the + matching task branch. Do not ask for additional confirmations afterward. +- `/task backlog` remains local. It creates no Issue, branch, commit, or PR. +- This standing authorization applies only to the exact resolved task and its + deterministic branch. It does not authorize unrelated repository, Issue, PR, + branch-protection, release, or history-rewrite changes. + +## Identity And Naming + +- Every non-backlog task and child task must have one immutable `Tracking Key` + and one full GitHub Issue URL in `Public Tracking`. +- Use the hidden Issue marker + `` and the bounded canonical task + link defined by the shared `/task` workflow. Search all Issues for the marker + before creating anything; reuse exactly one valid match and block on ambiguity. +- Use Issue title `[] `. +- Use branch `task/-`. Normalize the existing task + slug to lowercase ASCII kebab-case and do not invent alternate branches on + retries. +- The PR title must follow the repository Conventional Commit rule. The PR body + must link the Issue and canonical task path and list the verification commands. + Include the canonical task key marker. Use an Issue reference, not an automatic + `Closes` keyword, because completion closes the Issue before PR creation. + +## `/task spec` + +1. Inspect the worktree, refuse to start a second specification when unrelated + changes exist, then create or update the canonical local task file. One + uncommitted target task document may carry forward into its `impl` branch. +2. Resolve and validate the fixed GitHub repository and `GH_TOKEN` contract. +3. Reconcile by Tracking Key across all Issues, including closed Issues and + excluding pull requests. +4. Reuse one valid linked Issue or create it immediately and non-interactively + with the one-sentence Goal plus canonical-link block. Do not show a preview or + ask for another approval. +5. Read the Issue back, require one exact valid marker match, then persist its full + URL in `Public Tracking`. Keep the task `blocked` when creation or read-back is + uncertain; retries must reconcile before creating again. +6. Do not create the task branch during `spec`. + +Apply the same behavior to top-level and child tasks. Existing non-backlog tasks +without an Issue must be linked automatically the next time `spec`, `impl`, or +task-aware `save` touches them. Historical completed tasks do not need bulk +backfill unless they are reopened. + +## `/task impl` + +1. Require a clean worktree except for the resolved task file created or updated + by the immediately preceding specification step. Stop on unrelated changes. +2. Ensure the Issue exists and passes the exact linkage validation above. +3. Refresh GitHub `main`, Gitea `origin/main`, and local `main`. Continue only when + both remote base refs are identical and local `main` can be updated by + fast-forward. Never merge divergent base branches or rewrite either `main`. +4. Create or reuse the deterministic task branch from that synchronized `main`. + A reused branch must belong to the same task and Tracking Key. +5. Mark the local task `in progress`, then implement and verify only that task. +6. Run the shared learn and submodule-refresh steps, include their relevant task + changes, and repeat affected verification when they change the task diff. +7. After successful verification, automatically execute the task publication + lifecycle below. `/task impl` must not stop merely to suggest `/save`. + +## Task-Aware `/save` + +- Require an attached `HEAD`, inspect the current branch, active chat, changed + paths, commits since the `main` merge base, task files, and intended save scope, + then resolve exactly one local task. A matching task branch or one changed + canonical task file is strong identity; do not guess from a coincidental task + id or similar title. +- When no task resolves, or existing tasks do not uniquely cover the complete + intended diff, propose one concise retrospective task title, Goal, and file + scope and ask whether to create it. This is the only extra approval in the + automated save path. If declined, stop without a commit, Issue, branch, or + remote mutation. +- After approval, allocate the next unused task id from files and Git history, + create the canonical task document with a random immutable Tracking Key, and + create and validate its GitHub Issue through the mandatory `/task spec` linkage + rules. Implementation preceding the task record is valid in this retrospective + path. Never reuse an existing id or combine unrelated changes merely to avoid a + second task. +- For an existing resolved task without a valid Issue URL, create and validate + its mandatory Issue automatically before branch creation. If Issue creation or + read-back is uncertain, mark the task `blocked` and stop before committing. +- Derive the deterministic `task/-` branch after task and Issue identity + are valid. When already on that exact branch, continue. Otherwise create it at + the current `HEAD` and switch to it while preserving the intended uncommitted + changes. This is allowed from `main` and from another attached branch. +- Reuse an existing local or remote deterministic branch only when its task id, + Tracking Key, and Issue match exactly. Block on conflicting ownership instead + of creating an alternate branch name. +- Branching from the current `HEAD` does not make that point the final merge base. + After committing, refresh both remote `main` refs and rebase the task branch + onto their synchronized `main` as required by the publication lifecycle. +- Run the shared learn and submodule-refresh steps before committing, but keep all + changes scoped to the resolved task. +- After verification, use the publication lifecycle below instead of the shared + direct-push or base-branch save paths. Never push task work directly to `main`. + +## Publication Lifecycle + +This lifecycle is used by successful `/task impl`, task-aware `/save`, and the +cancel path where explicitly noted. + +1. Revalidate the Issue, task path, task id, Tracking Key, branch name, clean + scope, and both current remote `main` SHAs. Require GitHub and Gitea `main` to + identify the same commit before completion starts. +2. For solved work, close the Issue with `gh issue close --reason completed` and + read it back before writing local status `solved`. For cancellation, close it + with `gh issue close --reason "not planned"`, require API state reason + `not_planned`, and write status `cancelled` plus the cancellation reason. +3. Record verification in the task file, stage only task-related changes, and + create a focused Conventional Commit through the repository commit-message + guard. If commit creation fails after Issue closure, reopen the Issue and keep + the task blocked. +4. Rebase the task branch onto the still-current synchronized `main` when needed. + If the rebase changes commits already pushed for this task, fetch first and use + `--force-with-lease` only for the task branch. +5. Push the exact task branch to Gitea `origin` and to the fixed GitHub repository. + Verify both branch refs equal local HEAD. +6. Search PRs in all states by exact head branch and canonical task key before + creation. Reuse the sole matching open PR, accept a matching merged PR as a + recovery state, or reopen the sole matching closed-unmerged PR when safe. + Create only when none exists. Block on multiple or conflicting matches. The + Issue, task path, Tracking Key, head, and base must all match. +7. Poll for a bounded maximum of ten minutes until GitHub reports at least one + required check, then wait non-interactively with `gh pr checks --required + --watch --fail-fast`. A failed, cancelled, skipped, missing, or timed-out + required check blocks merging. +8. Squash-merge the PR with `gh pr merge --squash --delete-branch`. Do not use a + merge commit, direct protected-branch push, admin bypass, or force push to + `main`. +9. Read the PR back and require `MERGED` state plus a merge commit on GitHub + `main`. Confirm the Issue remains closed with the expected reason. +10. Fetch GitHub `main`; require Gitea `origin/main` to be an ancestor, then update + Gitea `main` by normal fast-forward push only. Stop rather than rewrite Gitea + `main` if it diverged. +11. Update local `main` by fast-forward in the worktree that owns it, without + disturbing another dirty worktree. Verify local, GitHub, and Gitea `main` all + identify the same commit. +12. Delete the exact task branch from GitHub, Gitea, and locally only after merge + and three-way `main` equality are verified. Squash merge means local deletion + may require `git branch -D`; this is authorized only for the verified merged + task branch. + +If PR creation, checks, merge, or synchronization fails after an Issue was closed, +reopen the Issue, set the local task to `blocked`, preserve the branch and PR for +retry, and report the exact non-secret blocker. Never create a duplicate Issue, +branch, or PR during recovery. + +## `/task cancel` + +- Ensure the Issue exists and validate linkage. +- Create or reuse the deterministic task branch from synchronized `main` when no + implementation branch exists. +- Close the Issue with reason `not_planned`, write `cancelled` plus the reason in + the task file, and run the publication lifecycle through a small cancellation + PR and normal squash merge. +- Delete the task branch on both hosts and locally only after the cancellation PR + is merged and both `main` refs are synchronized. + +## Safety And Idempotency + +- Before every remote mutation, read current state and compare exact repository, + task key, branch, Issue, PR, and expected SHA values. +- Never use `--force` and never force-push `main`. `--force-with-lease` is limited + to a previously pushed task branch after its rebase. +- Never disable branch protection, required checks, conversation resolution, + linear history, or branch deletion/force-push restrictions. +- Never merge while required checks are pending or unsuccessful. +- Never include secrets, raw Issue bodies from unrelated Issues, tokens, or raw + mirror API responses in output or durable files. +- Report Issue URL, branch, PR URL, check result, merge commit, synchronization + result, and branch deletion result at completion. diff --git a/Taskfile.yml b/Taskfile.yml index c16a76b..9f5c9d7 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -1,7 +1,8 @@ # Taskfile.yml - root entrypoint for repo task shortcuts. # -# Includes the CLI module Taskfile without flattening or aliases so commands stay -# namespaced, for example `task cli:check` from the repository root. +# Includes application Taskfiles without flattening or aliases so commands stay +# namespaced, for example `task cli:check` or `task go:test` from the repository +# root. version: '3' @@ -9,3 +10,6 @@ includes: cli: taskfile: ./app/codegeist/cli/Taskfile.yml dir: ./app/codegeist/cli + go: + taskfile: ./app/codegeist/go/Taskfile.yml + dir: ./app/codegeist/go diff --git a/app/codegeist/go/README.md b/app/codegeist/go/README.md new file mode 100644 index 0000000..19f791b --- /dev/null +++ b/app/codegeist/go/README.md @@ -0,0 +1,12 @@ +# Codegeist Go + +Minimal greenfield Go project for the future Codegeist application. + +```bash +task test +task build +task run +``` + +From the repository root, prefix these tasks with `go:`, for example +`task go:test`. diff --git a/app/codegeist/go/Taskfile.yml b/app/codegeist/go/Taskfile.yml new file mode 100644 index 0000000..fa1d608 --- /dev/null +++ b/app/codegeist/go/Taskfile.yml @@ -0,0 +1,22 @@ +# Taskfile.yml - minimal build, test, and run entrypoints for the Go project. +# +# Commands run from this directory directly or through the root `go` namespace. + +version: '3' + +tasks: + test: + desc: Test the Go project + cmds: + - go test ./... + + build: + desc: Build the Go application + cmds: + - mkdir -p bin + - go build -o bin/codegeist . + + run: + desc: Run the Go application + cmds: + - go run . diff --git a/app/codegeist/go/go.mod b/app/codegeist/go/go.mod new file mode 100644 index 0000000..936ebfd --- /dev/null +++ b/app/codegeist/go/go.mod @@ -0,0 +1,3 @@ +module github.com/codegeist-ai/codegeist/app/codegeist/go + +go 1.26.0 diff --git a/app/codegeist/go/main.go b/app/codegeist/go/main.go new file mode 100644 index 0000000..38dd16d --- /dev/null +++ b/app/codegeist/go/main.go @@ -0,0 +1,3 @@ +package main + +func main() {} diff --git a/docs/developer/architecture/architecture.md b/docs/developer/architecture/architecture.md index 2f1fab6..800a92c 100644 --- a/docs/developer/architecture/architecture.md +++ b/docs/developer/architecture/architecture.md @@ -43,8 +43,13 @@ docs: ## Current System State -Codegeist currently contains one Java/Spring Boot CLI application under -`app/codegeist/cli`. Implemented runtime behavior is Spring Boot application +Codegeist currently contains the existing Java/Spring Boot CLI application under +`app/codegeist/cli` and a separate minimal greenfield Go project under +`app/codegeist/go`. The Go project currently provides only an empty executable +entrypoint plus local test, build, and run tasks; it has no agent, CLI-command, +TUI, provider, tool, configuration, or session behavior yet. + +Implemented Java runtime behavior is Spring Boot application startup, typed provider config loading and validation from an explicit path or working-directory `codegeist.yml`, trusted local SpEL preprocessing, direct workspace, tools, and MCP config loading, active workspace resolution, provider-neutral chat execution @@ -110,6 +115,10 @@ app/codegeist/cli/ pom.xml Taskfile.yml src/... +app/codegeist/go/ + go.mod + main.go + Taskfile.yml scripts/tests/ smoke-common.ps1 install-script-smoke.ps1 diff --git a/docs/tasks/README.md b/docs/tasks/README.md index d8b43fc..4f7ec31 100644 --- a/docs/tasks/README.md +++ b/docs/tasks/README.md @@ -4,6 +4,8 @@ Repository-local task files preserve implementation detail that does not fit in GitHub issue. They are working specifications and historical records, not a standalone public backlog. +GitHub Mirror: https://github.com/codegeist-ai/codegeist + Read [`CONTRIBUTING.md`](../../CONTRIBUTING.md) before starting implementation. Codegeist also uses the account-wide [Code of Conduct](https://github.com/codegeist-ai/.github/blob/main/CODE_OF_CONDUCT.md), @@ -50,14 +52,21 @@ Codegeist Roadmap -> repository Issue -> repository task file -> branch -> PR -> - Every issue marked ready for implementation should link its canonical task path. - Every publicly tracked task should replace `pending issue creation` with the full GitHub issue URL. -- A pull request should link the issue and task, report verification, and close the - issue when the implementation is complete. Update the task status in the same - implementation unit when practical. +- Every accepted non-backlog task and child task receives one GitHub Issue. Its + implementation uses one task branch and one pull request. +- Automation closes a solved Issue as completed before opening the PR, waits for + required checks, squash-merges the PR, synchronizes GitHub and Gitea `main`, and + deletes the task branch from both hosts and locally. +- Cancellation closes the Issue as not planned and records the cancelled task + state through a small automated PR before the same synchronization and cleanup. +- `/save` may create the deterministic task branch from the current branch. When + implemented work has no unique task yet, it first asks whether to create a + retrospective task; accepting creates both the local task and mandatory Issue + before publication continues. -Ideas do not need a task and issue immediately. Create both when maintainers accept -the work for implementation and need a durable contract. Do not mirror an entire -task specification into an issue body, and do not advertise historical, deferred, -or merely open task records as ready work. +Backlog ideas remain local until promoted to accepted tasks. Do not mirror an +entire task specification into an issue body, and do not advertise historical or +deferred task records as ready work. ## Current Contributor Foundation Work diff --git a/docs/tasks/T014_bootstrap-go-project-and-automated-task-lifecycle.md b/docs/tasks/T014_bootstrap-go-project-and-automated-task-lifecycle.md new file mode 100644 index 0000000..99a3fa9 --- /dev/null +++ b/docs/tasks/T014_bootstrap-go-project-and-automated-task-lifecycle.md @@ -0,0 +1,87 @@ +# T014 Bootstrap Go Project And Automated Task Lifecycle + +Status: solved +Public Tracking: https://github.com/codegeist-ai/codegeist/issues/12 +Tracking Key: 91b650bb-ff2b-42f1-81b2-c7ba768c6c50 + +## Goal + +Establish the minimal Go application scaffold and repository task commands while +making GitHub Issue, task-branch, PR, merge, Gitea synchronization, and cleanup +mandatory and automated. + +## Context + +Implementation preceded this retrospective task record. The approved save scope +combines the initial greenfield Go bootstrap with the repository-local workflow +needed to publish accepted work through protected GitHub pull requests while +keeping the Gitea source remote synchronized. + +## Scope + +- Add the minimal Go module and empty application entrypoint under + `app/codegeist/go/`. +- Add module-local test, build, and run tasks and expose them through the root + `go:` Taskfile namespace. +- Add and register the Codegeist-specific GitHub task lifecycle rule. +- Make mandatory Issue creation, deterministic task branches, checked squash PR + merges, dual-host synchronization, and branch cleanup automatic for `/task` + and `/save`. +- Document the fixed GitHub mirror and retrospective `/save` behavior. +- Include the shared `.devcontainer` release gitlink refreshed by the save + workflow. + +## Files + +- `app/codegeist/go/**` +- `Taskfile.yml` +- `.oc_local/opencode.json` +- `.oc_local/rules/codegeist-task-specification.md` +- `.oc_local/rules/github-task-lifecycle.md` +- `docs/tasks/README.md` +- `docs/developer/architecture/architecture.md` +- `.devcontainer` + +## Non-Goals + +- Do not implement AI-agent, provider, CLI-command, or TUI behavior in Go. +- Do not migrate Java source or runtime contracts into the Go project. +- Do not bypass GitHub branch protection or required checks. +- Do not rewrite either remote `main` branch. + +## Acceptance Criteria + +- The Go module builds, runs, passes `go test`, and has no external dependencies. +- Root Taskfile commands `go:test`, `go:build`, and `go:run` delegate to the Go + module. +- Every accepted non-backlog task uses one mandatory Issue, deterministic task + branch, checked squash PR, and automated branch cleanup. +- `/save` can create a task branch from the current attached branch and asks once + before creating a retrospective task and its mandatory Issue when no unique + task exists. +- GitHub and Gitea `main` remain identical after automated publication. + +## Verification + +Run: + +```bash +task go:test +task go:build +task go:run +jq empty .oc_local/opencode.json +git --no-pager diff --check +``` + +## Verification Result + +- `task go:test`, `task go:build`, and `task go:run` passed. +- `go vet ./...` passed from `app/codegeist/go`; `go list -m all` reported only + the Codegeist Go module and no external dependencies. +- `task cli:check` passed with 202 tests, 0 failures, 0 errors, and 6 expected + provider-gated skips; its test phase completed in 41.309 seconds and package + phase in 4.826 seconds. +- Taskfile discovery, `.oc_local/opencode.json` parsing and lifecycle-rule + registration, and `git --no-pager diff --check` passed. +- `.opencode` and `.devcontainer` were refreshed to their configured clean + `release` branches before publication.