Conversation
Sync with master
* Ensures that the `postgres_data/` directory and its contents are excluded from version control. * Prevents accidental commits of local PostgreSQL data files.
Remove outdated RELEASE_v0.2.0 documentation and add new RELEASE_v0.3…
feat(TaskCard): display task ID in the TaskCard component
* feat: add daily standup and agent heartbeat models, migrations, and Vue components - Implemented DailyStandup and AgentHeartbeat models in Go with necessary fields. - Created SQL migrations for daily_standups and agent_heartbeats tables with indexes. - Developed StandupModal component for submitting and editing daily standups with form validation. - Added standupStore for managing standup data, including fetching, creating, updating, and deleting standups. - Created Standups view to display a list of daily standups with filtering options and modal integration. - Enhanced UI with loading states, error handling, and markdown rendering for standup details. * fix(go.mod): remove 'indirect' comments from dependency requirements * feat(migrations): implement automatic migration system with tracking and bootstrap scripts * feat: add release notes for v0.3.5 including daily standup management and migration system * Initial plan * Initial plan * Initial plan * Add application verification report for v0.3.5 --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Release v0.3.5 adds a daily standup management feature (UI + API + schema) and introduces a startup-time migration runner with helper scripts, alongside task reassignment and A2A agent-card compatibility updates.
Changes:
- Added Daily Standups + Agent Heartbeats: new DB tables, Go handlers/models, and Vue UI (view + modal + store) with markdown rendering.
- Implemented a migration runner on server startup plus PowerShell/SQL bootstrap tooling for existing databases.
- Added task reassignment (UI + REST endpoint) and updated A2A agent-card parsing/tests for the newer schema.
Reviewed changes
Copilot reviewed 32 out of 34 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| web/src/views/Standups.vue | New standups dashboard view (filtering, markdown rendering, CRUD actions). |
| web/src/views/ProjectDetail.vue | Adds task reassignment modal wiring and client-side reassignment request. |
| web/src/stores/standupStore.js | New Pinia store for standup CRUD + heartbeat APIs. |
| web/src/services/api.js | Adds API client methods for standups and heartbeats. |
| web/src/router/index.js | Registers the /standups route. |
| web/src/components/TaskCard.vue | Adds reassign action + truncates task description. |
| web/src/components/StandupModal.vue | New modal for creating/editing standups. |
| web/src/components/ReassignModal.vue | New modal for selecting a new assignee for a task. |
| web/src/App.vue | Adds navigation link to the Standups view. |
| tests/a2a/integration_test.go | Updates integration assertions for new agent-card capabilities schema. |
| tests/a2a/external_agent_test.go | Updates real-world/legacy parsing tests and adds extra nil checks. |
| tests/a2a/agent_card_test.go | Updates unit tests for new schema/legacy capabilities handling. |
| scripts/create-migration.ps1 | New helper to scaffold numbered migration SQL files. |
| scripts/bootstrap-migrations.ps1 | New helper to bootstrap existing DBs into the migration system. |
| migrations/bootstrap_existing_db.sql | One-time bootstrap SQL to create/seed schema_migrations. |
| migrations/003_daily_standups.sql | Adds daily_standups and agent_heartbeats tables + indexes. |
| internal/models/task.go | Adds ReassignTaskRequest model for task reassignment endpoint. |
| internal/models/standup.go | Adds standup + heartbeat models and request types. |
| internal/models/models_test.go | Updates model tests to include more assertions/initialization changes. |
| internal/mcp/handler.go | Adds websocket hub to MCP handler + new reassign_task tool and broadcasting. |
| internal/handlers/tasks.go | Adds PUT /tasks/{id}/reassign handler and websocket broadcast. |
| internal/handlers/standups.go | New HTTP handlers for standups + heartbeats. |
| internal/a2a/models/agent_card.go | Updates custom JSON unmarshal logic to handle legacy capabilities formats. |
| go.mod | Promotes several dependencies from indirect to direct requirements. |
| docs/releases/RELEASE_v0.3.5.md | Adds v0.3.5 release notes. |
| docs/VERIFICATION_REPORT_v0.3.5.md | Adds verification report for v0.3.5. |
| docs/MIGRATION_IMPLEMENTATION.md | Documents the migration system implementation. |
| docs/MIGRATIONS.md | Documents migration usage, conventions, and troubleshooting. |
| docs/DAILY_STANDUP_QUICK_REFERENCE.md | Quick reference for standup APIs/UI usage. |
| docs/DAILY_STANDUP_FEATURE.md | Full documentation for the Daily Standup feature. |
| cmd/server/main.go | Wires new handlers/routes and implements directory-based migration runner. |
| README.md | Adds “Database & Migrations” section and usage instructions. |
| .gitignore | Ignores /.vs directory. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@copilot open a new pull request to apply changes based on the comments in this thread |
|
@techbuzzz I've opened a new pull request, #12, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@techbuzzz I've opened a new pull request, #13, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@techbuzzz I've opened a new pull request, #14, to work on those changes. Once the pull request is ready, I'll request review from you. |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
@techbuzzz I've opened a new pull request, #15, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@techbuzzz I've opened a new pull request, #16, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@techbuzzz I've opened a new pull request, #17, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@techbuzzz I've opened a new pull request, #18, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@techbuzzz I've opened a new pull request, #19, to work on those changes. Once the pull request is ready, I'll request review from you. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 36 out of 45 changed files in this pull request and generated 9 comments.
Files not reviewed (1)
- web/package-lock.json: Language not supported
Comments suppressed due to low confidence (1)
web/src/views/Standups.vue:360
- This view still renders
standup.references, but the backend now returnsreference_links. Update the view (and any related store normalization) to use the new field, or map/alias the API response so existing UI continues to work.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Acquire advisory lock to prevent concurrent migrations | ||
| // Use a fixed integer key for migrations lock (hash of "agent-shaker-migrations") | ||
| const migrationLockKey = 918273645 | ||
|
|
||
| // Try to acquire advisory lock (non-blocking) | ||
| var lockAcquired bool | ||
| err := db.QueryRow("SELECT pg_try_advisory_lock($1)", migrationLockKey).Scan(&lockAcquired) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to acquire migration lock: %w", err) | ||
| } | ||
|
|
||
| if !lockAcquired { | ||
| log.Println("Another instance is running migrations, waiting...") | ||
| // Block until we can acquire the lock | ||
| _, err = db.Exec("SELECT pg_advisory_lock($1)", migrationLockKey) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to wait for migration lock: %w", err) | ||
| } | ||
| } | ||
|
|
||
| // Ensure we release the lock when done | ||
| defer func() { | ||
| _, err := db.Exec("SELECT pg_advisory_unlock($1)", migrationLockKey) | ||
| if err != nil { | ||
| log.Printf("Warning: failed to release migration lock: %v", err) | ||
| } | ||
| }() |
There was a problem hiding this comment.
The advisory lock is acquired/released via db.QueryRow/db.Exec on a pooled *sql.DB. Advisory locks are session (connection) scoped, so acquiring on one connection and unlocking on another can leak the lock (or fail to actually serialize migrations). Use a dedicated *sql.Conn (db.Conn(ctx)) or a single transaction/connection to acquire and defer-unlock on the same session, and close the conn when done.
There was a problem hiding this comment.
@copilot open a new pull request to apply changes based on this feedback
| -- Create daily_standups table | ||
| CREATE TABLE IF NOT EXISTS daily_standups ( |
There was a problem hiding this comment.
This migration file starts with a UTF-8 BOM (the invisible character before --). Some tooling/drivers treat this as a non-whitespace character and can break the first statement/comment. Remove the BOM so the first line begins with plain --.
There was a problem hiding this comment.
@copilot open a new pull request to apply changes based on this feedback
| ID uuid.UUID `json:"id" db:"id"` | ||
| AgentID uuid.UUID `json:"agent_id" db:"agent_id"` | ||
| ProjectID uuid.UUID `json:"project_id" db:"project_id"` | ||
| StandupDate time.Time `json:"standup_date" db:"standup_date"` | ||
| Did string `json:"did" db:"did"` // What I did yesterday | ||
| Doing string `json:"doing" db:"doing"` // What I'm doing today | ||
| Done string `json:"done" db:"done"` // What I plan to complete | ||
| Blockers string `json:"blockers" db:"blockers"` // Any blockers | ||
| Challenges string `json:"challenges" db:"challenges"` // Current challenges | ||
| ReferenceLinks string `json:"reference_links" db:"reference_links"` // Links, docs, etc. | ||
| CreatedAt time.Time `json:"created_at" db:"created_at"` | ||
| UpdatedAt time.Time `json:"updated_at" db:"updated_at"` | ||
| } | ||
|
|
||
| // CreateStandupRequest represents a request to create a daily standup | ||
| type CreateStandupRequest struct { | ||
| AgentID uuid.UUID `json:"agent_id"` | ||
| ProjectID uuid.UUID `json:"project_id"` | ||
| StandupDate string `json:"standup_date"` // YYYY-MM-DD format | ||
| Did string `json:"did"` | ||
| Doing string `json:"doing"` | ||
| Done string `json:"done"` | ||
| Blockers string `json:"blockers"` | ||
| Challenges string `json:"challenges"` | ||
| References string `json:"references"` | ||
| AgentID uuid.UUID `json:"agent_id"` | ||
| ProjectID uuid.UUID `json:"project_id"` | ||
| StandupDate string `json:"standup_date"` // YYYY-MM-DD format | ||
| Did string `json:"did"` | ||
| Doing string `json:"doing"` | ||
| Done string `json:"done"` | ||
| Blockers string `json:"blockers"` | ||
| Challenges string `json:"challenges"` | ||
| ReferenceLinks string `json:"reference_links"` | ||
| } |
There was a problem hiding this comment.
The standup JSON field was renamed from references to reference_links. The current frontend (e.g., StandupModal/Standups view) still sends/reads references, so this will break standup create/update and display. To preserve backward compatibility (as stated in the release notes), keep the JSON name as references (while mapping to DB column reference_links) or accept both references and reference_links in request payloads.
There was a problem hiding this comment.
@copilot open a new pull request to apply changes based on this feedback
| const formatDate = (dateString) => { | ||
| const date = new Date(dateString) | ||
| // Treat as date-only value to avoid timezone shifts | ||
| if (!dateString) return '' | ||
|
|
||
| const dateOnly = dateString.includes('T') ? dateString.split('T')[0] : dateString | ||
| const parts = dateOnly.split('-') | ||
|
|
||
| if (parts.length !== 3) { | ||
| // Fallback to standard parsing if format is unexpected | ||
| return new Date(dateString).toLocaleDateString('en-US', { | ||
| weekday: 'long', | ||
| year: 'numeric', | ||
| month: 'long', | ||
| day: 'numeric' | ||
| }) | ||
| } | ||
|
|
||
| const [year, month, day] = parts.map(Number) | ||
| const date = new Date(year, month - 1, day) // Use local timezone with specific date parts | ||
| return date.toLocaleDateString('en-US', { |
There was a problem hiding this comment.
formatDate can still throw RangeError: Invalid time value if dateString is in YYYY-MM-DD shape but contains non-numeric parts (Number(...) => NaN) or out-of-range values. Consider validating that year/month/day are finite and within expected ranges before constructing the Date, and fall back to the standard parsing path when invalid.
There was a problem hiding this comment.
@copilot open a new pull request to apply changes based on this feedback
| import { useMcpSetup, downloadFile, downloadAllMcpFiles } from '../composables/useMcpSetup' | ||
| import api from '../services/api' |
There was a problem hiding this comment.
downloadFile and downloadAllMcpFiles are imported from ../composables/useMcpSetup but the implementation uses the versions returned by useMcpSetup(...) instead (shadowing the imports). This makes the module imports unused and confusing—remove the unused named imports or rename to avoid shadowing.
There was a problem hiding this comment.
@copilot open a new pull request to apply changes based on this feedback
| case '.mcp': | ||
| downloadFile('.mcp.json', config.mcpVSCodeJson, 'application/json') | ||
| break |
There was a problem hiding this comment.
The .mcp download case is using config.mcpVSCodeJson, which will download the VS Code config under the .mcp.json filename. This should use config.mcpVS2026Json so the downloaded content matches the preview/intent for Visual Studio 2026.
There was a problem hiding this comment.
@copilot open a new pull request to apply changes based on this feedback
| ### 1. **VS 2026 Dedicated Configuration** (`mcpVS2026Json`) | ||
| - Full-featured MCP server configuration optimized for Visual Studio 2026 | ||
| - Includes schema reference for VS 2026 compatibility | ||
| - Comprehensive tool definitions and endpoints | ||
| - Enhanced security and logging configuration | ||
|
|
||
| ### 2. **Root Directory `.mcp.json`** | ||
| - Auto-generated `.mcp.json` file for project root | ||
| - Recognized automatically by Visual Studio 2026 | ||
| - No manual configuration required after extraction | ||
| - Includes full environment context (project, agent, capabilities) | ||
|
|
||
| ### 3. **Direct Project Integration** | ||
| - New `copyMcpFilesToProject()` function writes files directly to project | ||
| - No need to manually copy or extract files | ||
| - Automatic directory structure creation | ||
| - API-based file management | ||
|
|
||
| ### 4. **Multi-IDE Support** | ||
| Generates configuration for: | ||
| - **Visual Studio 2026** - `.mcp.json` in project root | ||
| - **VS Code** - `.vscode/settings.json` and `.vscode/mcp.json` | ||
| - **Command Line** - PowerShell and Bash scripts | ||
| - **GitHub Copilot** - `.github/copilot-instructions.md` | ||
|
|
||
| ## Configuration Files Generated | ||
|
|
||
| ### `.mcp.json` (Visual Studio 2026 - Root Directory) | ||
| ```json | ||
| { | ||
| "$schema": "https://aka.ms/mcp-server-schema", | ||
| "version": "1.0.0", | ||
| "servers": { | ||
| "agent-shaker": { | ||
| "type": "http", | ||
| "url": "http://localhost:8080?project_id=...&agent_id=...", | ||
| "name": "Agent Shaker MCP Server", | ||
| "capabilities": ["resources", "tools", "prompts", "context-sharing"], | ||
| "tools": [...], | ||
| "resources": {...}, | ||
| "security": {...}, | ||
| "logging": {...} | ||
| } | ||
| } | ||
| } | ||
| ``` |
There was a problem hiding this comment.
The docs claim mcpVS2026Json generates a full schema-aware config with tools/resources/security/logging, but the current generator in useMcpSetup.js only emits a minimal servers -> { type, url } structure. Please either update the generator to match the documented output or tone down the documentation/examples so they reflect the actual generated JSON.
There was a problem hiding this comment.
@copilot open a new pull request to apply changes based on this feedback
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
@techbuzzz I've opened a new pull request, #33, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@techbuzzz I've opened a new pull request, #34, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@techbuzzz I've opened a new pull request, #35, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@techbuzzz I've opened a new pull request, #36, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@techbuzzz I've opened a new pull request, #37, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@techbuzzz I've opened a new pull request, #38, to work on those changes. Once the pull request is ready, I'll request review from you. |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
@techbuzzz I've opened a new pull request, #39, to work on those changes. Once the pull request is ready, I'll request review from you. |
* Initial plan * Fix advisory lock to use dedicated connection for session scope Co-authored-by: techbuzzz <6938100+techbuzzz@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: techbuzzz <6938100+techbuzzz@users.noreply.github.com>
* Initial plan * Remove UTF-8 BOM from migrations/003_daily_standups.sql Co-authored-by: techbuzzz <6938100+techbuzzz@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: techbuzzz <6938100+techbuzzz@users.noreply.github.com>
…up models (#35) * Initial plan * Fix backward compatibility: change JSON tag from reference_links to references Co-authored-by: techbuzzz <6938100+techbuzzz@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: techbuzzz <6938100+techbuzzz@users.noreply.github.com>
…36) * Initial plan * Add validation for formatDate to prevent RangeError with invalid dates Co-authored-by: techbuzzz <6938100+techbuzzz@users.noreply.github.com> * Improve date validation: add rollover check and error handling Co-authored-by: techbuzzz <6938100+techbuzzz@users.noreply.github.com> * Refactor formatDate: extract fallback parsing to eliminate duplication Co-authored-by: techbuzzz <6938100+techbuzzz@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: techbuzzz <6938100+techbuzzz@users.noreply.github.com>
* Initial plan * Remove unused downloadFile and downloadAllMcpFiles imports Co-authored-by: techbuzzz <6938100+techbuzzz@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: techbuzzz <6938100+techbuzzz@users.noreply.github.com>
* Initial plan * Fix .mcp download to use VS2026 config instead of VSCode config Co-authored-by: techbuzzz <6938100+techbuzzz@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: techbuzzz <6938100+techbuzzz@users.noreply.github.com>
* Initial plan * Update VS2026 docs to match actual minimal config implementation Co-authored-by: techbuzzz <6938100+techbuzzz@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: techbuzzz <6938100+techbuzzz@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 36 out of 45 changed files in this pull request and generated 6 comments.
Files not reviewed (1)
- web/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Change to temp directory for migration discovery | ||
| oldWd, _ := os.Getwd() | ||
| migrationsDir := filepath.Join(tmpDir, "migrations") | ||
| if err := os.Mkdir(migrationsDir, 0755); err != nil { | ||
| t.Fatalf("Failed to create migrations dir: %v", err) | ||
| } | ||
| if err := os.WriteFile(filepath.Join(migrationsDir, "001_test.sql"), []byte(migrationSQL), 0644); err != nil { | ||
| t.Fatalf("Failed to create migration in migrations dir: %v", err) | ||
| } | ||
| defer os.Chdir(oldWd) | ||
| os.Chdir(tmpDir) | ||
|
|
There was a problem hiding this comment.
This test ignores errors from os.Getwd() and os.Chdir(tmpDir). If either fails, the test may behave unpredictably and the deferred Chdir(oldWd) could also misbehave. Please check both errors (and consider using t.Cleanup for restoring the working directory).
| // Build MCP URL with project and agent context | ||
| const baseUrl = urlValue.replace('/api', '') | ||
| const mcpUrl = `${baseUrl}?project_id=${projectValue.id}&agent_id=${agentValue.id}` | ||
|
|
||
| const config = { | ||
| "mcpServers": { | ||
| "servers": { | ||
| "agent-shaker": { | ||
| "url": mcpUrl, | ||
| "type": "http", | ||
| "metadata": { | ||
| "name": "Agent Shaker MCP Server", | ||
| "version": "1.0.0", | ||
| "description": "Multi-agent coordination platform for collaborative development", | ||
| "capabilities": [ | ||
| "resources", | ||
| "tools", | ||
| "prompts", | ||
| "context-sharing" | ||
| ] | ||
| }, | ||
| "project": { | ||
| "id": project.value.id, | ||
| "name": project.value.name, | ||
| "description": project.value.description || "", | ||
| "status": project.value.status, | ||
| "type": "multi-agent" | ||
| }, | ||
| "agent": { | ||
| "id": agent.value.id, | ||
| "name": agent.value.name, | ||
| "role": agent.value.role, | ||
| "team": agent.value.team || "default", | ||
| "status": agent.value.status | ||
| } | ||
| "url": mcpUrl | ||
| } | ||
| } |
There was a problem hiding this comment.
mcpVSCodeJson / .vscode/mcp.json is generated with a top-level servers key, but parts of the existing documentation in this repo still describe a mcpServers key (e.g. docs/MCP_JSON_CONFIG.md:15, docs/COPILOT_MCP_INTEGRATION.md:278). Please reconcile these formats (update docs and/or generate a backward-compatible structure) to avoid users producing non-working MCP configs.
| // MCP Setup configuration using composable | ||
| const mcpApiUrl = computed(() => { | ||
| return `${window.location.protocol}//${window.location.host}/api` | ||
| return `${window.location.protocol}//${window.location.hostname}:8080` | ||
| }) |
There was a problem hiding this comment.
mcpApiUrl is hard-coded to window.location.hostname:8080, which drops the current port (if any) and ignores the UI’s configurable backend URL (see web/src/services/api.js using localStorage['mcp-server-url']). This will produce incorrect MCP URLs in non-local deployments or when a custom server URL is set. Consider deriving the MCP base from the same configured server URL (or at least use window.location.host/window.location.origin without hard-coding port 8080).
| The implementation now uses PostgreSQL's `INSERT ... ON CONFLICT DO NOTHING RETURNING` pattern to atomically claim migrations: | ||
|
|
||
| ```go | ||
| var claimedVersion string | ||
| err = db.QueryRow( | ||
| `INSERT INTO schema_migrations (version, applied_at) | ||
| VALUES ($1, CURRENT_TIMESTAMP) | ||
| ON CONFLICT (version) DO NOTHING | ||
| RETURNING version`, | ||
| entry.Name(), | ||
| ).Scan(&claimedVersion) | ||
|
|
||
| if err != nil { | ||
| // sql.ErrNoRows means ON CONFLICT happened - another instance claimed this | ||
| log.Printf("Migration %s already claimed by another instance, skipping", entry.Name()) | ||
| continue | ||
| } | ||
|
|
||
| // Only the instance that successfully claimed the migration reaches here | ||
| // and executes the DDL | ||
| ``` | ||
|
|
||
| ### How It Works | ||
|
|
||
| 1. Each instance attempts to insert a row into `schema_migrations` for the migration | ||
| 2. The `ON CONFLICT DO NOTHING` clause prevents errors if the row already exists | ||
| 3. The `RETURNING version` clause returns the version only if the INSERT succeeded | ||
| 4. If another instance already claimed the migration: | ||
| - `ON CONFLICT` prevents the insert | ||
| - No rows are returned | ||
| - `Scan()` returns `sql.ErrNoRows` | ||
| - The instance safely skips this migration | ||
| 5. Only one instance will successfully claim and execute each migration | ||
|
|
||
| ### Benefits | ||
|
|
||
| - **No race conditions**: The database enforces atomicity | ||
| - **No crashes**: Concurrent instances gracefully skip already-claimed migrations | ||
| - **Simple**: No need for advisory locks or external coordination | ||
| - **Docker-safe**: Works correctly with `docker-compose up --scale app=3` | ||
| - **Production-safe**: Multiple pods/containers can start simultaneously | ||
|
|
||
| ### Trade-offs | ||
|
|
||
| - Migrations are no longer wrapped in a single transaction | ||
| - The tracking row is inserted *before* executing the DDL | ||
| - If a migration fails: | ||
| - The tracking row remains (prevents re-attempts) | ||
| - Manual intervention is required to fix and continue | ||
| - This is intentional: failed migrations should not auto-retry |
There was a problem hiding this comment.
The migration concurrency documentation describes an INSERT ... ON CONFLICT DO NOTHING RETURNING “claim then run” approach and explicitly says migrations are not transactional / the row is inserted before DDL, but the current implementation in cmd/server/main.go uses a session-scoped advisory lock and runs each migration inside a DB transaction before inserting into schema_migrations. Please update this doc to match the actual implementation (or update the implementation to match the doc), otherwise operators will be misled about failure modes and recovery steps.
| - Auto-generated `.mcp.json` file for project root | ||
| - Recognized automatically by Visual Studio 2026 | ||
| - No manual configuration required after extraction | ||
| - Includes full environment context (project, agent, capabilities) |
There was a problem hiding this comment.
This bullet claims the generated .mcp.json includes “full environment context (project, agent, capabilities)”, but the example (and the current generator) only includes server type + a URL with project_id/agent_id query params. Please reword to match what is actually generated (or extend the generator if capabilities/context are intended to be embedded in the file).
| - Includes full environment context (project, agent, capabilities) | |
| - Includes MCP server type and URL with project and agent identifiers; additional capabilities are provided dynamically by the server or can be added if needed |
| // POST /api/projects/{projectId}/mcp-files | ||
| func CreateMcpFiles(w http.ResponseWriter, r *http.Request) { | ||
| projectId := mux.Vars(r)["projectId"] | ||
|
|
||
| var req struct { | ||
| Files map[string]string `json:"files"` | ||
| } | ||
|
|
||
| json.NewDecoder(r.Body).Decode(&req) | ||
|
|
||
| // Create directories | ||
| os.MkdirAll(filepath.Join(projectDir, ".vscode"), 0755) | ||
| os.MkdirAll(filepath.Join(projectDir, ".github"), 0755) | ||
| os.MkdirAll(filepath.Join(projectDir, "scripts"), 0755) | ||
|
|
||
| // Write files | ||
| for path, content := range req.Files { | ||
| fullPath := filepath.Join(projectDir, path) | ||
| ioutil.WriteFile(fullPath, []byte(content), 0644) | ||
| } | ||
|
|
||
| // Return success | ||
| json.NewEncoder(w).Encode(map[string]interface{}{ | ||
| "success": true, | ||
| "files": keys(req.Files), | ||
| }) |
There was a problem hiding this comment.
The sample implementation of the CreateMcpFiles endpoint writes files using a user-controlled path from req.Files directly into filepath.Join(projectDir, path) without any validation or restriction. If this pattern is implemented as shown, an attacker who can call this endpoint could supply values like "../../../../etc/cron.d/malicious" as keys in files, leading to path traversal and arbitrary file writes outside the intended project directory. To avoid this, constrain path to a fixed allowlist of expected filenames (e.g., specific MCP config files), normalize and verify that fullPath remains within projectDir, and reject any input containing .., absolute paths, or unexpected directory separators before writing to disk.
| // POST /api/projects/{projectId}/mcp-files | |
| func CreateMcpFiles(w http.ResponseWriter, r *http.Request) { | |
| projectId := mux.Vars(r)["projectId"] | |
| var req struct { | |
| Files map[string]string `json:"files"` | |
| } | |
| json.NewDecoder(r.Body).Decode(&req) | |
| // Create directories | |
| os.MkdirAll(filepath.Join(projectDir, ".vscode"), 0755) | |
| os.MkdirAll(filepath.Join(projectDir, ".github"), 0755) | |
| os.MkdirAll(filepath.Join(projectDir, "scripts"), 0755) | |
| // Write files | |
| for path, content := range req.Files { | |
| fullPath := filepath.Join(projectDir, path) | |
| ioutil.WriteFile(fullPath, []byte(content), 0644) | |
| } | |
| // Return success | |
| json.NewEncoder(w).Encode(map[string]interface{}{ | |
| "success": true, | |
| "files": keys(req.Files), | |
| }) | |
| // allowedMcpFiles defines the only files that can be written by this endpoint. | |
| var allowedMcpFiles = map[string]struct{}{ | |
| ".vscode/mcp.json": {}, | |
| ".github/workflows/mcp.yml": {}, | |
| "scripts/setup-mcp.sh": {}, | |
| } | |
| // POST /api/projects/{projectId}/mcp-files | |
| func CreateMcpFiles(w http.ResponseWriter, r *http.Request) { | |
| projectId := mux.Vars(r)["projectId"] | |
| var req struct { | |
| Files map[string]string `json:"files"` | |
| } | |
| if err := json.NewDecoder(r.Body).Decode(&req); err != nil { | |
| http.Error(w, "invalid request body", http.StatusBadRequest) | |
| return | |
| } | |
| // Create directories | |
| if err := os.MkdirAll(filepath.Join(projectDir, ".vscode"), 0755); err != nil { | |
| http.Error(w, "failed to create .vscode directory", http.StatusInternalServerError) | |
| return | |
| } | |
| if err := os.MkdirAll(filepath.Join(projectDir, ".github"), 0755); err != nil { | |
| http.Error(w, "failed to create .github directory", http.StatusInternalServerError) | |
| return | |
| } | |
| if err := os.MkdirAll(filepath.Join(projectDir, "scripts"), 0755); err != nil { | |
| http.Error(w, "failed to create scripts directory", http.StatusInternalServerError) | |
| return | |
| } | |
| // Write files (using a fixed allowlist to prevent path traversal) | |
| for path, content := range req.Files { | |
| if _, ok := allowedMcpFiles[path]; !ok { | |
| http.Error(w, "invalid file path", http.StatusBadRequest) | |
| return | |
| } | |
| fullPath := filepath.Join(projectDir, path) | |
| if err := ioutil.WriteFile(fullPath, []byte(content), 0644); err != nil { | |
| http.Error(w, "failed to write file", http.StatusInternalServerError) | |
| return | |
| } | |
| } | |
| // Return success | |
| if err := json.NewEncoder(w).Encode(map[string]interface{}{ | |
| "success": true, | |
| "files": keys(req.Files), | |
| }); err != nil { | |
| http.Error(w, "failed to encode response", http.StatusInternalServerError) | |
| return | |
| } |
Release v0.3.5 – Daily Standup Management & Production Migrations
Release Date: January 27, 2026
Target Branch:
mainSource Branch:
devStatus: Ready for production deployment
1. Overview
Release v0.3.5 delivers a production-ready Daily Standup Management system for distributed teams and a robust database migration framework to safely evolve the schema over time. The release is designed to be 100% backward compatible with the previous version (v0.3.0), with a strong focus on stability, observability, and maintainability.
2. Highlights
2.1 Daily Standup Management System
New functionality to support daily standups and team coordination:
Standup entries with:
Did / Doing / Done
Blockers
Challenges
References / links
Per-agent, per-day standup records with uniqueness guarantees
Agent heartbeat tracking for health/online status
RESTful APIs for CRUD operations and querying standups
Frontend views for standup creation, editing, and overview
2.2 Production-Grade Migration System
A new migration mechanism to safely evolve the database schema:
Transactional migrations (all-or-nothing)
Migration tracking table to avoid re-applying the same migration
Idempotent, deterministic execution
Helper scripts to create and bootstrap migrations
Designed to be safe in containerized / concurrent environments
3. Changes Summary
3.1 Backend
Features:
Added models and handlers for:
daily_standups– stores daily standup data per agentagent_heartbeats– stores heartbeat events/statusAdded endpoints (examples, may vary by implementation):
POST /api/standups– create/update standup (UPSERT)GET /api/standups– list standups with filters (project, agent, date)GET /api/standups/{id}– get single standupPUT /api/standups/{id}– update standupDELETE /api/standups/{id}– delete standupPOST /api/heartbeats– record heartbeatGET /api/agents/{id}/heartbeats– list heartbeats for an agentMigration framework:
New
schema_migrationstable to track executed migrationsMigrations executed transactionally on startup
Skips already-applied migrations based on version identifiers
3.2 Database Schema
New tables (conceptual schema):
Indexes (recommended):
4. Frontend
New Standups view (dashboard) for:
Viewing standups by project/agent/date
Navigating through historical standups
New Standup modal/form for:
Creating and editing standups
Writing content using markdown
State management/store updated to:
Load, cache, and update standup data
Handle loading/error states
XSS protection for rendered markdown (e.g. DOMPurify or equivalent)
5. Scripts & Tooling
New scripts to manage migrations (names may vary; examples):
create-migration– scaffold a new migration with auto-incremented versionbootstrap-migrations– bootstrap an existing database into the migration systemStartup logic:
Runs all pending migrations on app start
Logs migration versions and timing
6. Quality & Testing
Unit tests: All existing tests passing, new tests added for:
Standup creation, update, and querying
Heartbeat recording and listing
Migration application logic
Integration tests: Exercise API flows for:
Creating standups
Listing standups with filters
Recording and listing heartbeats
Static checks: Linters / analyzers (
go vetor equivalents) are cleanPerformance: Endpoint latencies verified to be within acceptable limits for typical payload sizes
7. Backward Compatibility
No breaking changes:
Existing endpoints remain unchanged
No removals of existing tables/columns
New tables and endpoints are additive
The migration framework:
Only adds schema; does not drop or alter existing required fields in a breaking way
Is safe to run on existing databases after bootstrap
8. Deployment Notes
8.1 Prerequisites
Database access with permissions to:
Create tables
Create indexes
Insert into migration tracking table
Ability to restart application services
8.2 Upgrade Steps (from previous version)
If migration tracking does not exist yet, run the bootstrap script once (if provided in your repo):
# Example; adjust path/name to your repo ./scripts/bootstrap-migrations.shor, if running directly:
Call health endpoint (if available), for example:
Open the UI and ensure the new Standups section is visible
Create a test standup and check it persists as expected
9. Security Considerations
Input validation added/updated on new endpoints
Standup markdown rendering is sanitized to mitigate XSS
SQL operations use parameterized queries
Important for production:
Ensure authentication/authorization is enabled for standup endpoints
Serve the application over HTTPS
Consider rate limiting and logging/monitoring for the new APIs
10. Known Limitations / Future Work
No built-in analytics yet for standups (e.g., trends, metrics per team)
Heartbeat data currently provides basic status; richer status/health dashboards can be added later
Migrations are focused on schema; data migrations might need additional conventions or tooling in future versions
11. Summary
Release v0.3.5 is a safe, backward-compatible update that introduces:
A complete daily standup management flow (backend + frontend)
A production-grade migration system for long-term maintainability
Additional tests and safeguards to keep the codebase stable
This version is recommended for deployment to
mainas the baseline for future feature work.