chore: bootstrap rdb-discovery
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"project_name": "rdb-discovery",
|
||||
"stage": "DISCOVERY",
|
||||
"current_task": "TASK-000",
|
||||
"next_task": "TASK-001"
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
# Agent Handoff
|
||||
|
||||
## Current Stage
|
||||
|
||||
DISCOVERY
|
||||
|
||||
## Current Task
|
||||
|
||||
TASK-000 — Bootstrap RDB project standards
|
||||
|
||||
## Instructions For Agent
|
||||
|
||||
- Complete one task only
|
||||
- Make the smallest useful change
|
||||
- Update documentation
|
||||
- Run tests
|
||||
- Commit changes
|
||||
- Stop after task completion
|
||||
@@ -0,0 +1,10 @@
|
||||
# Project State
|
||||
|
||||
Current Stage: DISCOVERY
|
||||
Previous Stage: NONE
|
||||
Next Stage: BOOTSTRAP_READY
|
||||
|
||||
Current Task: TASK-000
|
||||
Active Branch: main
|
||||
|
||||
Last Updated: 2026-06-01
|
||||
@@ -0,0 +1,44 @@
|
||||
# rdb-discovery
|
||||
|
||||
A small CLI-first tool for repeatable software project discovery and delivery.
|
||||
|
||||
It creates markdown files that help humans and AI coding agents understand:
|
||||
|
||||
- what is being built
|
||||
- why it exists
|
||||
- what questions remain open
|
||||
- what task should be done next
|
||||
- what stage the project is currently in
|
||||
|
||||
## Install for local development
|
||||
|
||||
```bash
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install -e '.[dev]'
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
rdb init
|
||||
rdb discover
|
||||
rdb status
|
||||
rdb next
|
||||
rdb start TASK-001
|
||||
rdb complete TASK-001
|
||||
rdb handoff
|
||||
```
|
||||
|
||||
## Bootstrap workflow
|
||||
|
||||
1. Run `rdb init`
|
||||
2. Run `rdb discover`
|
||||
3. Run `rdb status`
|
||||
4. Run `rdb next`
|
||||
5. Give the next task to Claude Code or Cline
|
||||
6. Commit after each completed task
|
||||
|
||||
## Principle
|
||||
|
||||
Markdown files are the source of truth. No database is required.
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
Run Log
|
||||
2026-06-01
|
||||
Bootstrap project structure created.
|
||||
@@ -0,0 +1,23 @@
|
||||
# TASKS
|
||||
|
||||
## TASK-000 — Bootstrap RDB project standards
|
||||
|
||||
Status: Todo
|
||||
|
||||
Goal: Add the project control files used by RDB agent workflows.
|
||||
|
||||
Acceptance Criteria:
|
||||
|
||||
- PROJECT_STATE.md exists
|
||||
- AGENT_HANDOFF.md exists
|
||||
- .rdb/project.json exists
|
||||
- context/repository-context.md exists
|
||||
- TEST_PLAN.md exists
|
||||
- RUN_LOG.md exists
|
||||
- README.md explains the structure
|
||||
|
||||
## TASK-001 — Implement rdb init
|
||||
|
||||
Status: Todo
|
||||
|
||||
Goal: Create the command that initialises the standard RDB project structure.
|
||||
@@ -0,0 +1,17 @@
|
||||
# Test Plan
|
||||
|
||||
## Bootstrap Validation
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install -e '.[dev]'
|
||||
pytest
|
||||
rdb --help
|
||||
|
||||
Expected result:
|
||||
|
||||
Tests pass
|
||||
CLI help displays
|
||||
@@ -0,0 +1,269 @@
|
||||
# `/context/agent-guidelines.md`
|
||||
|
||||
# Agent Operating Guidelines
|
||||
|
||||
This file defines how AI coding agents should behave when working on RDB Solutions Ltd projects.
|
||||
|
||||
These rules apply to:
|
||||
|
||||
- OpenHands
|
||||
- Claude Code
|
||||
- Cursor Agents
|
||||
- Copilot Agents
|
||||
- Local coding agents
|
||||
- Future autonomous development systems
|
||||
|
||||
---
|
||||
|
||||
# Core Rule
|
||||
|
||||
Make the smallest useful change possible.
|
||||
|
||||
Agents should favour many small successful changes over large risky changes.
|
||||
|
||||
---
|
||||
|
||||
# Before Starting Work
|
||||
|
||||
Agents should first read:
|
||||
|
||||
```text
|
||||
/context/company-context.md
|
||||
/context/infrastructure-context.md
|
||||
/context/development-context.md
|
||||
README.md
|
||||
ARCHITECTURE.md
|
||||
TASKS.md
|
||||
```
|
||||
|
||||
If these files exist.
|
||||
|
||||
---
|
||||
|
||||
# Task Execution Model
|
||||
|
||||
Work should be completed using backlog items.
|
||||
|
||||
Recommended process:
|
||||
|
||||
1. Select task
|
||||
2. Understand task
|
||||
3. Implement task
|
||||
4. Test task
|
||||
5. Document task
|
||||
6. Commit task
|
||||
7. Move to next task
|
||||
|
||||
Avoid combining unrelated tasks.
|
||||
|
||||
---
|
||||
|
||||
# Safe Change Policy
|
||||
|
||||
Agents should:
|
||||
|
||||
✅ Add functionality
|
||||
|
||||
✅ Fix defects
|
||||
|
||||
✅ Improve documentation
|
||||
|
||||
✅ Add tests
|
||||
|
||||
✅ Refactor locally
|
||||
|
||||
Agents should not:
|
||||
|
||||
❌ Rewrite entire systems
|
||||
|
||||
❌ Replace frameworks
|
||||
|
||||
❌ Change infrastructure architecture
|
||||
|
||||
❌ Change deployment methods
|
||||
|
||||
❌ Delete large amounts of code
|
||||
|
||||
Without explicit approval.
|
||||
|
||||
---
|
||||
|
||||
# Code Generation Standards
|
||||
|
||||
Generated code should:
|
||||
|
||||
- Be readable
|
||||
- Be maintainable
|
||||
- Follow existing project patterns
|
||||
- Include error handling
|
||||
- Include logging where appropriate
|
||||
|
||||
Avoid:
|
||||
|
||||
- Clever code
|
||||
- Unnecessary abstractions
|
||||
- Premature optimisation
|
||||
|
||||
---
|
||||
|
||||
# Infrastructure Changes
|
||||
|
||||
Infrastructure changes require higher scrutiny.
|
||||
|
||||
Examples:
|
||||
|
||||
- Jenkins
|
||||
- Gitea
|
||||
- Supabase
|
||||
- Reverse proxies
|
||||
- DNS
|
||||
- Production deployments
|
||||
|
||||
For infrastructure work:
|
||||
|
||||
1. Explain proposed change
|
||||
2. Explain risk
|
||||
3. Explain rollback
|
||||
4. Generate implementation plan
|
||||
|
||||
Do not execute destructive changes automatically.
|
||||
|
||||
---
|
||||
|
||||
# Git Rules
|
||||
|
||||
Preferred workflow:
|
||||
|
||||
```text
|
||||
Create branch
|
||||
Make change
|
||||
Run tests
|
||||
Commit
|
||||
Create PR
|
||||
```
|
||||
|
||||
Commit frequently.
|
||||
|
||||
Commit messages should be descriptive.
|
||||
|
||||
---
|
||||
|
||||
# Testing Requirements
|
||||
|
||||
Where practical:
|
||||
|
||||
- Unit tests
|
||||
- Integration tests
|
||||
- Build validation
|
||||
|
||||
Agents should never claim testing was performed if it was not.
|
||||
|
||||
Use:
|
||||
|
||||
```text
|
||||
Verified
|
||||
```
|
||||
|
||||
Only when actually verified.
|
||||
|
||||
Use:
|
||||
|
||||
```text
|
||||
Not tested
|
||||
```
|
||||
|
||||
When testing was not possible.
|
||||
|
||||
---
|
||||
|
||||
# Documentation Requirements
|
||||
|
||||
If behaviour changes:
|
||||
|
||||
Update:
|
||||
|
||||
- README
|
||||
- Architecture docs
|
||||
- API docs
|
||||
- Task status
|
||||
|
||||
where applicable.
|
||||
|
||||
Documentation is part of the task.
|
||||
|
||||
---
|
||||
|
||||
# Autonomous Work Limits
|
||||
|
||||
Agents may autonomously:
|
||||
|
||||
- Create files
|
||||
- Modify files
|
||||
- Add tests
|
||||
- Add documentation
|
||||
- Refactor small areas
|
||||
|
||||
Agents should request approval before:
|
||||
|
||||
- Deleting files
|
||||
- Deleting databases
|
||||
- Deploying to production
|
||||
- Changing authentication
|
||||
- Changing networking
|
||||
- Modifying CI/CD pipelines
|
||||
|
||||
---
|
||||
|
||||
# Preferred Deliverables
|
||||
|
||||
When completing work, agents should provide:
|
||||
|
||||
## Summary
|
||||
|
||||
What was changed.
|
||||
|
||||
## Files Modified
|
||||
|
||||
List of modified files.
|
||||
|
||||
## Validation
|
||||
|
||||
Tests executed and results.
|
||||
|
||||
## Risks
|
||||
|
||||
Potential side effects.
|
||||
|
||||
## Next Recommended Task
|
||||
|
||||
Small logical follow-up task.
|
||||
|
||||
---
|
||||
|
||||
# RDB-Specific Preferences
|
||||
|
||||
Remember:
|
||||
|
||||
- Gitea over GitHub
|
||||
- Jenkins over cloud CI systems
|
||||
- Docker preferred
|
||||
- Proxmox preferred
|
||||
- Local LLMs preferred
|
||||
- Self-hosted services preferred
|
||||
- Incremental change preferred
|
||||
|
||||
Do not recommend cloud replacements unless there is a significant advantage.
|
||||
|
||||
---
|
||||
|
||||
# Success Criteria
|
||||
|
||||
A task is complete when:
|
||||
|
||||
- Requirements are met
|
||||
- Tests pass
|
||||
- Documentation is updated
|
||||
- Changes are understandable
|
||||
- Rollback is possible
|
||||
|
||||
Optimise for maintainability and long-term ownership rather than speed alone.
|
||||
@@ -0,0 +1,40 @@
|
||||
# `/context/company-context.md`
|
||||
|
||||
# RDB Solutions Ltd Context
|
||||
|
||||
RDB Solutions Ltd is developing internal and customer-facing software systems with a strong preference for self-hosted infrastructure, local control, and practical automation.
|
||||
|
||||
The company favours owning its development stack rather than depending heavily on third-party SaaS platforms where avoidable.
|
||||
|
||||
## Goals
|
||||
|
||||
The main goals are:
|
||||
|
||||
- Improve development efficiency
|
||||
- Use local and self-hosted tools where practical
|
||||
- Automate repetitive development and deployment tasks
|
||||
- Support LLM-assisted development
|
||||
- Maintain control over source code, infrastructure, and data
|
||||
- Build systems that are maintainable by a small team or solo developer
|
||||
|
||||
## Preferred Approach
|
||||
|
||||
RDB Solutions Ltd prefers:
|
||||
|
||||
- Self-hosted Git using Gitea
|
||||
- Jenkins for CI/CD
|
||||
- Docker-based deployments
|
||||
- Proxmox for virtualisation
|
||||
- Local LLMs where possible
|
||||
- Clear task files and backlog-driven agent work
|
||||
- Incremental changes over large risky rewrites
|
||||
- Documentation that allows AI tools to understand the system quickly
|
||||
|
||||
## General Constraints
|
||||
|
||||
- Avoid assuming GitHub is used.
|
||||
- Prefer Gitea-compatible workflows.
|
||||
- Prefer local or self-hosted services where practical.
|
||||
- Avoid vendor lock-in unless there is a clear benefit.
|
||||
- Keep systems understandable and maintainable.
|
||||
- Prefer simple architecture before complex orchestration.
|
||||
@@ -0,0 +1,542 @@
|
||||
# `/context/current-environment.md`
|
||||
|
||||
# Current Environment
|
||||
|
||||
Last Updated: 2026-06-01
|
||||
|
||||
This file describes the current live RDB Solutions infrastructure.
|
||||
|
||||
Update whenever hardware, VMs, services, networking, or development tooling changes.
|
||||
|
||||
---
|
||||
|
||||
# Network Overview
|
||||
|
||||
## Primary Site
|
||||
|
||||
Location:
|
||||
|
||||
- <Office/Home Lab>
|
||||
|
||||
Internet:
|
||||
|
||||
- ISP: Lightening Fibre
|
||||
- Download: 2.5 Gbps
|
||||
- Router: Zyxel EX5601-T0
|
||||
- Internal Wifi Extender: Deco
|
||||
- Static IP: 212.221.168.135
|
||||
|
||||
Domain(s):
|
||||
|
||||
- rdbsolutions.co.uk
|
||||
- gitea.rdbcloud.co.uk
|
||||
- prox.rdbcloud.co.uk
|
||||
- pedw.rdbcloud.co.uk
|
||||
|
||||
Internal Network:
|
||||
|
||||
```text
|
||||
LAN: 192.168.x.0/24
|
||||
Gateway: 192.168.x.1
|
||||
DNS: AdGuard
|
||||
DHCP: <device>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Physical Infrastructure
|
||||
|
||||
## Proxmox Host
|
||||
|
||||
Hostname:
|
||||
|
||||
- proxmox01
|
||||
|
||||
Purpose:
|
||||
|
||||
- Primary virtualisation host
|
||||
|
||||
Hardware:
|
||||
|
||||
CPU:
|
||||
|
||||
- <model>
|
||||
|
||||
RAM:
|
||||
|
||||
- 16 GB
|
||||
|
||||
Storage:
|
||||
|
||||
- <details>
|
||||
|
||||
Network:
|
||||
|
||||
- <IP>
|
||||
|
||||
Notes:
|
||||
|
||||
- Hosts infrastructure VMs and LXCs
|
||||
- Main internal services
|
||||
|
||||
---
|
||||
|
||||
## AI / Ollama Server
|
||||
|
||||
Hostname:
|
||||
|
||||
- rdbUltra
|
||||
|
||||
Purpose:
|
||||
|
||||
- Local LLM hosting
|
||||
|
||||
Hardware:
|
||||
|
||||
CPU:
|
||||
|
||||
- Intel I9
|
||||
|
||||
RAM:
|
||||
|
||||
- 32 GB
|
||||
|
||||
GPU:
|
||||
|
||||
- RTX 5070 Ti
|
||||
- 16 GB VRAM
|
||||
|
||||
Network:
|
||||
|
||||
- 192.168.1.111
|
||||
|
||||
Services:
|
||||
|
||||
- Ollama
|
||||
|
||||
Models Installed:
|
||||
|
||||
- Qwen3
|
||||
- Qwen Coder
|
||||
- <others>
|
||||
|
||||
Endpoints:
|
||||
|
||||
```text
|
||||
http://<ip>:11434
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Development Workstation
|
||||
|
||||
Hostname:
|
||||
|
||||
- rdbmacbook
|
||||
|
||||
Type:
|
||||
|
||||
- Intel MacBook Pro
|
||||
|
||||
Purpose:
|
||||
|
||||
- Main software development workstation
|
||||
|
||||
Installed Tools:
|
||||
|
||||
- VS Code
|
||||
- Claude Code
|
||||
- Docker
|
||||
- Git
|
||||
- SSH
|
||||
|
||||
---
|
||||
|
||||
## OpenWebUI Host
|
||||
|
||||
Hostname:
|
||||
|
||||
- rdboffice
|
||||
|
||||
Purpose:
|
||||
|
||||
- Browser-based LLM interface
|
||||
|
||||
Connected To:
|
||||
|
||||
- Ollama Server
|
||||
|
||||
URL:
|
||||
|
||||
```text
|
||||
https://ai.rdbcloud.co.uk
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Virtual Machines
|
||||
|
||||
## VM Inventory
|
||||
|
||||
| VM Name | Purpose | CPU | RAM | IP |
|
||||
| ---------- | -------- | --- | ---- | ------- |
|
||||
| supabase01 | Database | 4 | 8 GB | x.x.x.x |
|
||||
|
||||
---
|
||||
|
||||
# LXC Containers
|
||||
|
||||
## Container Inventory
|
||||
|
||||
| IP | LXC Name | Proxmox ID | RAM |
|
||||
|------------------------------------------------------------------------------------
|
||||
| 192.168.68.100 | adguard | 100 (LXC) | 512 MB
|
||||
| 192.168.68.102 | gitea | 104 (LXC) | 1.00 GB
|
||||
| 192.168.68.79 | nginxproxymanager | 105 (LXC) | 1.00 GB
|
||||
| 192.168.68.90 | jenkins | 106 (LXC) | 2.00 GB
|
||||
|
||||
---
|
||||
|
||||
# Infrastructure Services
|
||||
|
||||
## AdGuard
|
||||
|
||||
Purpose:
|
||||
|
||||
- DNS
|
||||
- Ad Blocking
|
||||
|
||||
URL:
|
||||
|
||||
```text
|
||||
http://adguard.lan
|
||||
```
|
||||
|
||||
Host:
|
||||
|
||||
- adguard01
|
||||
|
||||
Port:
|
||||
|
||||
- 3000
|
||||
|
||||
---
|
||||
|
||||
## Gitea
|
||||
|
||||
Purpose:
|
||||
|
||||
- Git repositories
|
||||
- Source control
|
||||
|
||||
URL:
|
||||
|
||||
```text
|
||||
https://gitea.rdbcloud.co.uk
|
||||
```
|
||||
|
||||
Host:
|
||||
|
||||
- https://gitea.rdbcloud.co.uk
|
||||
|
||||
Version:
|
||||
|
||||
- v1.25.0
|
||||
|
||||
Repositories:
|
||||
|
||||
- RC Compatibility App
|
||||
- RDB Mobile App
|
||||
- Infrastructure
|
||||
- robbond/pedwFrontend
|
||||
- robbond/proxmox-monitor
|
||||
- robbond/pleskSaas
|
||||
- robbond/pedwV2
|
||||
- robbond/rc-compat
|
||||
- robbond/gacapi
|
||||
|
||||
---
|
||||
|
||||
## Jenkins
|
||||
|
||||
Purpose:
|
||||
|
||||
- CI/CD
|
||||
|
||||
URL:
|
||||
|
||||
```text
|
||||
http://jenkins.lan:8080
|
||||
```
|
||||
|
||||
Host:
|
||||
|
||||
- jenkins.lan
|
||||
|
||||
Jobs:
|
||||
|
||||
- RC Compatibility Build
|
||||
- Mobile App Build
|
||||
- Docker Deployments
|
||||
- PEDW testing pipeline
|
||||
|
||||
---
|
||||
|
||||
## Supabase
|
||||
|
||||
Purpose:
|
||||
|
||||
- PostgreSQL
|
||||
- Authentication
|
||||
- Storage
|
||||
|
||||
Host:
|
||||
|
||||
- supabase01
|
||||
|
||||
Environment:
|
||||
|
||||
- Self-hosted
|
||||
|
||||
Database Version:
|
||||
|
||||
- PostgreSQL xx
|
||||
|
||||
---
|
||||
|
||||
## Nginx Proxy Manager
|
||||
|
||||
Purpose:
|
||||
|
||||
- Reverse Proxy
|
||||
- SSL
|
||||
|
||||
Host:
|
||||
|
||||
- npm01
|
||||
|
||||
Managed Hosts:
|
||||
|
||||
| Hostname | Target |
|
||||
| ------------------------- | -------------------------- |
|
||||
| \*.coolify.rdbcloud.co.uk | https://192.168.68.115:443 |
|
||||
| ai.rdbcloud.co.uk | http://192.168.68.97:3001 |
|
||||
| coolify.rdbcloud.co.uk | http://192.168.68.115:8001 |
|
||||
| gitea.rdbcloud.co.uk | http://192.168.68.102:3000 |
|
||||
| gitmcp.rdbcloud.co.uk | http://192.168.68.180:8080 |
|
||||
| ha.rdbcloud.co.uk | http://192.168.68.96:8123 |
|
||||
| jellyfin.rdbcloud.co.uk | http://192.168.68.101:8096 |
|
||||
| nextcloud.rdbcloud.co.uk | http://192.168.68.55:80 |
|
||||
| pedw.rdbcloud.co.uk | http://192.168.68.109:3000 |
|
||||
| portal.rdbcloud.co.uk | http://192.168.68.116:3000 |
|
||||
| prox.rdbcloud.co.uk | https://192.168.68.70:8006 |
|
||||
| supabase.rdbcloud.co.uk | http://192.168.68.115:8000 |
|
||||
|
||||
---
|
||||
|
||||
# Development Stack
|
||||
|
||||
## Source Control
|
||||
|
||||
Primary:
|
||||
|
||||
- Gitea
|
||||
|
||||
Workflow:
|
||||
|
||||
```text
|
||||
Developer
|
||||
↓
|
||||
Feature Branch
|
||||
↓
|
||||
Commit
|
||||
↓
|
||||
Pull Request
|
||||
↓
|
||||
Merge
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CI/CD
|
||||
|
||||
Primary:
|
||||
|
||||
- Jenkins
|
||||
|
||||
Build Flow:
|
||||
|
||||
```text
|
||||
Gitea
|
||||
↓
|
||||
Jenkins
|
||||
↓
|
||||
Tests
|
||||
↓
|
||||
Docker Build
|
||||
↓
|
||||
Deploy
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Containers
|
||||
|
||||
Runtime:
|
||||
|
||||
- Docker
|
||||
- Docker Compose
|
||||
|
||||
Container Registry:
|
||||
|
||||
- <local registry>
|
||||
- Docker Hub
|
||||
- Gitea Registry
|
||||
|
||||
---
|
||||
|
||||
# AI Development Environment
|
||||
|
||||
## Local Models
|
||||
|
||||
| Model | Purpose |
|
||||
| ----------------- | ------- |
|
||||
| Qwen3.6:35b-a3b | Coding |
|
||||
| Qwen2.5-coder:14b | Coding |
|
||||
|
||||
---
|
||||
|
||||
## Agent Platforms
|
||||
|
||||
Installed:
|
||||
|
||||
- OpenWebUI
|
||||
- Claude Code
|
||||
- Cline in VScode
|
||||
|
||||
Planned:
|
||||
|
||||
- OpenHands
|
||||
|
||||
---
|
||||
|
||||
## OpenHands
|
||||
|
||||
Status:
|
||||
|
||||
- Planned / Testing / Production
|
||||
|
||||
Location:
|
||||
|
||||
- VM / LXC / Docker
|
||||
|
||||
Resources:
|
||||
|
||||
CPU:
|
||||
|
||||
- x
|
||||
|
||||
RAM:
|
||||
|
||||
- x GB
|
||||
|
||||
Connected Systems:
|
||||
|
||||
- Gitea
|
||||
- Jenkins
|
||||
- Ollama
|
||||
|
||||
---
|
||||
|
||||
# Security
|
||||
|
||||
## Secrets Storage
|
||||
|
||||
Current Method:
|
||||
|
||||
- <method>
|
||||
|
||||
Preferred Future:
|
||||
|
||||
- Vault
|
||||
- 1Password
|
||||
- Bitwarden
|
||||
- Environment Variables
|
||||
|
||||
---
|
||||
|
||||
## Backup Strategy
|
||||
|
||||
Infrastructure:
|
||||
|
||||
- Proxmox backups
|
||||
- VM snapshots
|
||||
|
||||
Repositories:
|
||||
|
||||
- Gitea backups
|
||||
|
||||
Databases:
|
||||
|
||||
- PostgreSQL backups
|
||||
|
||||
Frequency:
|
||||
|
||||
- Daily
|
||||
- Weekly
|
||||
- Monthly
|
||||
|
||||
---
|
||||
|
||||
# Monitoring
|
||||
|
||||
Current Tools:
|
||||
|
||||
- <tool>
|
||||
|
||||
Metrics:
|
||||
|
||||
- Host health
|
||||
- VM health
|
||||
- Disk usage
|
||||
- Jenkins status
|
||||
- Database health
|
||||
|
||||
---
|
||||
|
||||
# Known Constraints
|
||||
|
||||
Current Limitations:
|
||||
|
||||
1. Proxmox host has 16 GB RAM
|
||||
2. AI server has single GPU
|
||||
3. Limited staging environment
|
||||
4. <additional constraints>
|
||||
|
||||
---
|
||||
|
||||
# Improvement Opportunities
|
||||
|
||||
Potential Future Enhancements:
|
||||
|
||||
- Dedicated monitoring stack
|
||||
- Centralised logging
|
||||
- Local container registry
|
||||
- OpenHands integration
|
||||
- Automated deployment pipelines
|
||||
- Infrastructure-as-Code
|
||||
- Agent task orchestration
|
||||
|
||||
---
|
||||
|
||||
# Notes For AI Agents
|
||||
|
||||
When making recommendations:
|
||||
|
||||
- Prefer self-hosted solutions
|
||||
- Prefer Gitea integrations
|
||||
- Prefer Jenkins automation
|
||||
- Prefer Docker deployments
|
||||
- Consider current RAM limitations
|
||||
- Assume Ollama is available locally
|
||||
- Assume local AI workflows are preferred over cloud alternatives
|
||||
@@ -0,0 +1,294 @@
|
||||
# `/context/development-context.md`
|
||||
|
||||
# Development Environment Context
|
||||
|
||||
This document describes the preferred development workflow, tools, standards, and technology choices used by RDB Solutions Ltd.
|
||||
|
||||
AI coding assistants, IDE agents, and autonomous development tools should read this file before making recommendations or changes.
|
||||
|
||||
---
|
||||
|
||||
# Primary Development Workstation
|
||||
|
||||
## MacBook Pro (Intel)
|
||||
|
||||
Primary software development machine.
|
||||
|
||||
Typical activities:
|
||||
|
||||
- Application development
|
||||
- Repository management
|
||||
- Code reviews
|
||||
- Testing
|
||||
- Infrastructure administration
|
||||
- LLM-assisted development
|
||||
|
||||
---
|
||||
|
||||
# Source Control
|
||||
|
||||
## Gitea
|
||||
|
||||
Primary Git platform.
|
||||
|
||||
Preferences:
|
||||
|
||||
- Gitea is the source of truth.
|
||||
- Do not assume GitHub is available.
|
||||
- Do not recommend GitHub-specific workflows unless explicitly requested.
|
||||
- Pull Requests should be used for significant changes.
|
||||
- Commit messages should be clear and descriptive.
|
||||
|
||||
Preferred commit style:
|
||||
|
||||
```text
|
||||
feat: add VM status endpoint
|
||||
|
||||
fix: correct Jenkins deployment script
|
||||
|
||||
docs: update infrastructure documentation
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# CI/CD
|
||||
|
||||
## Jenkins
|
||||
|
||||
Primary automation platform.
|
||||
|
||||
Current and future responsibilities:
|
||||
|
||||
- Build applications
|
||||
- Run tests
|
||||
- Build Docker images
|
||||
- Deploy services
|
||||
- Run scheduled maintenance tasks
|
||||
- Execute agent-generated work after review
|
||||
|
||||
Preferred pipeline behaviour:
|
||||
|
||||
1. Pull code from Gitea
|
||||
2. Run validation
|
||||
3. Run tests
|
||||
4. Build artefacts
|
||||
5. Deploy to target environment
|
||||
|
||||
Agents should favour Jenkins automation over manual deployment procedures.
|
||||
|
||||
---
|
||||
|
||||
# Containerisation
|
||||
|
||||
## Docker
|
||||
|
||||
Preferred deployment format.
|
||||
|
||||
Goals:
|
||||
|
||||
- Consistent environments
|
||||
- Easier deployment
|
||||
- Simpler rollback
|
||||
- Portable services
|
||||
|
||||
When proposing software:
|
||||
|
||||
Prefer:
|
||||
|
||||
- Docker Compose
|
||||
- Single-container deployments
|
||||
- Simple architecture
|
||||
|
||||
Avoid:
|
||||
|
||||
- Kubernetes unless there is a clear requirement.
|
||||
|
||||
---
|
||||
|
||||
# Database Platforms
|
||||
|
||||
## PostgreSQL
|
||||
|
||||
Preferred database platform.
|
||||
|
||||
Current implementation:
|
||||
|
||||
- Supabase-hosted PostgreSQL
|
||||
|
||||
Preferred characteristics:
|
||||
|
||||
- Relational data model
|
||||
- Strong typing
|
||||
- Auditable schema changes
|
||||
|
||||
---
|
||||
|
||||
# IDEs and Editors
|
||||
|
||||
Current tools may include:
|
||||
|
||||
- VS Code
|
||||
- Cursor
|
||||
- Claude Code
|
||||
- OpenWebUI
|
||||
- Browser-based assistants
|
||||
|
||||
Recommendations should remain editor-agnostic where possible.
|
||||
|
||||
---
|
||||
|
||||
# Local LLM Infrastructure
|
||||
|
||||
## Ollama
|
||||
|
||||
Primary local inference platform.
|
||||
|
||||
Purpose:
|
||||
|
||||
- Local coding assistance
|
||||
- Experimentation
|
||||
- Agent backends
|
||||
- Development support
|
||||
|
||||
## Available Hardware
|
||||
|
||||
LLM Server:
|
||||
|
||||
- RTX 5070 Ti
|
||||
- 16 GB VRAM
|
||||
- 32 GB RAM
|
||||
|
||||
Agents should assume local inference is available.
|
||||
|
||||
---
|
||||
|
||||
# Preferred Models
|
||||
|
||||
Potential models include:
|
||||
|
||||
- Qwen Coder
|
||||
- Qwen3
|
||||
- DeepSeek Coder
|
||||
- Future coding-focused local models
|
||||
|
||||
Model selection should prioritise:
|
||||
|
||||
1. Code quality
|
||||
2. Reasoning ability
|
||||
3. Low operational cost
|
||||
4. Local execution
|
||||
|
||||
---
|
||||
|
||||
# AI-Assisted Development
|
||||
|
||||
RDB actively uses AI-assisted development.
|
||||
|
||||
Expected uses:
|
||||
|
||||
- Code generation
|
||||
- Refactoring
|
||||
- Documentation
|
||||
- Testing
|
||||
- Architecture review
|
||||
- Infrastructure planning
|
||||
|
||||
Agents should produce:
|
||||
|
||||
- Small reviewable changes
|
||||
- Clear reasoning
|
||||
- Minimal surprises
|
||||
|
||||
Avoid:
|
||||
|
||||
- Massive rewrites
|
||||
- Unrequested architecture changes
|
||||
- Hidden behaviour
|
||||
|
||||
---
|
||||
|
||||
# Task Management
|
||||
|
||||
Preferred approach:
|
||||
|
||||
Backlog-driven development.
|
||||
|
||||
Work should be decomposed into:
|
||||
|
||||
- Small tasks
|
||||
- Independent tasks
|
||||
- Reviewable tasks
|
||||
|
||||
Good example:
|
||||
|
||||
```text
|
||||
TASK-001
|
||||
Create API endpoint for VM status
|
||||
|
||||
TASK-002
|
||||
Add frontend status widget
|
||||
|
||||
TASK-003
|
||||
Write integration tests
|
||||
```
|
||||
|
||||
Avoid:
|
||||
|
||||
```text
|
||||
Rewrite the entire application
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Documentation Standards
|
||||
|
||||
Projects should contain:
|
||||
|
||||
```text
|
||||
README.md
|
||||
TASKS.md
|
||||
ARCHITECTURE.md
|
||||
CHANGELOG.md
|
||||
/context/
|
||||
```
|
||||
|
||||
Documentation should always be updated when functionality changes.
|
||||
|
||||
---
|
||||
|
||||
# Deployment Philosophy
|
||||
|
||||
Preferred order:
|
||||
|
||||
Development
|
||||
→ Test
|
||||
→ Staging
|
||||
→ Production
|
||||
|
||||
Production deployments should be repeatable and automated.
|
||||
|
||||
Avoid:
|
||||
|
||||
- Manual server modifications
|
||||
- Untracked configuration changes
|
||||
- Snowflake servers
|
||||
|
||||
---
|
||||
|
||||
# Development Principles
|
||||
|
||||
Prefer:
|
||||
|
||||
- Simplicity
|
||||
- Maintainability
|
||||
- Incremental improvements
|
||||
- Clear documentation
|
||||
- Automation
|
||||
- Reproducibility
|
||||
|
||||
Avoid:
|
||||
|
||||
- Unnecessary complexity
|
||||
- Vendor lock-in
|
||||
- Excessive dependencies
|
||||
- Platform-specific assumptions
|
||||
@@ -0,0 +1,193 @@
|
||||
# `/context/infrastructure-context.md`
|
||||
|
||||
# RDB Solutions Ltd Infrastructure Context
|
||||
|
||||
## Physical Machines
|
||||
|
||||
### Proxmox Server
|
||||
|
||||
Purpose:
|
||||
|
||||
- Main virtualisation host
|
||||
- Runs infrastructure services and VMs/LXCs
|
||||
|
||||
Current known services:
|
||||
|
||||
- AdGuard
|
||||
- Jenkins
|
||||
- Nginx Proxy Manager
|
||||
- Supabase VM
|
||||
- Potential future OpenHands runner
|
||||
|
||||
Current constraint:
|
||||
|
||||
- Proxmox host currently has 16 GB RAM, so resource allocation should be conservative.
|
||||
|
||||
Preferred usage:
|
||||
|
||||
- Infrastructure services
|
||||
- CI/CD
|
||||
- Reverse proxy
|
||||
- Databases
|
||||
- Lightweight agent runners
|
||||
- Isolated test environments
|
||||
|
||||
### LLM / Ollama Machine
|
||||
|
||||
Hardware:
|
||||
|
||||
- NVIDIA RTX 5070 Ti with 16 GB VRAM
|
||||
- 32 GB RAM
|
||||
|
||||
Purpose:
|
||||
|
||||
- Hosts Ollama
|
||||
- Runs local LLMs such as Qwen
|
||||
- Provides local model inference for development assistants and agent tooling
|
||||
|
||||
Preferred usage:
|
||||
|
||||
- Local coding models
|
||||
- Agent backend model provider
|
||||
- OpenWebUI integration
|
||||
- Possible API endpoint for tools like Claude Code-compatible wrappers or OpenHands
|
||||
|
||||
### MacBook Pro Intel
|
||||
|
||||
Purpose:
|
||||
|
||||
- Main development workstation
|
||||
|
||||
Preferred usage:
|
||||
|
||||
- IDE work
|
||||
- Local coding
|
||||
- Git commits
|
||||
- Testing frontend/mobile apps
|
||||
- Managing repositories and project files
|
||||
|
||||
### Mini PC
|
||||
|
||||
Purpose:
|
||||
|
||||
- Hosts OpenWebUI
|
||||
- Points to the Ollama machine for local LLM access
|
||||
|
||||
Preferred usage:
|
||||
|
||||
- Browser-based LLM interface
|
||||
- Local AI assistant access
|
||||
- Shared AI UI across the network
|
||||
|
||||
## Virtual Machines and Containers
|
||||
|
||||
### Jenkins
|
||||
|
||||
Purpose:
|
||||
|
||||
- CI/CD automation
|
||||
- Build pipelines
|
||||
- Test execution
|
||||
- Deployment workflows
|
||||
|
||||
Preferred future use:
|
||||
|
||||
- Pull code from Gitea
|
||||
- Build Docker images
|
||||
- Run tests
|
||||
- Deploy to hosted or self-hosted targets
|
||||
|
||||
### Gitea
|
||||
|
||||
Purpose:
|
||||
|
||||
- Self-hosted Git server
|
||||
- Source code control
|
||||
- Replacement for Bitbucket/GitHub where possible
|
||||
|
||||
Preferences:
|
||||
|
||||
- Use Gitea as the source of truth
|
||||
- Avoid GitHub-specific assumptions
|
||||
- Use issues, milestones, and pull requests where useful
|
||||
|
||||
### Supabase VM
|
||||
|
||||
Purpose:
|
||||
|
||||
- Database backend
|
||||
- Postgres services
|
||||
- Possible authentication/storage/API support depending on project needs
|
||||
|
||||
Preferred use:
|
||||
|
||||
- Application database
|
||||
- Internal APIs
|
||||
- Development/staging database
|
||||
- Storage where suitable
|
||||
|
||||
### Nginx Proxy Manager
|
||||
|
||||
Purpose:
|
||||
|
||||
- Reverse proxy
|
||||
- SSL termination
|
||||
- Routing internal services to friendly hostnames
|
||||
|
||||
Preferred use:
|
||||
|
||||
- Route apps and tools through internal domains
|
||||
- Manage certificates
|
||||
- Avoid exposing unnecessary services directly
|
||||
|
||||
### AdGuard
|
||||
|
||||
Purpose:
|
||||
|
||||
- DNS filtering
|
||||
- Local DNS support
|
||||
- Network-wide ad/tracker blocking
|
||||
|
||||
Potential use:
|
||||
|
||||
- Internal DNS names for services
|
||||
- Easier access to tools like Gitea, Jenkins, OpenWebUI, Supabase, etc.
|
||||
|
||||
## LLM and Agent Architecture
|
||||
|
||||
RDB Solutions Ltd is interested in using local LLMs and coding agents to improve productivity.
|
||||
|
||||
Candidate tools:
|
||||
|
||||
- Ollama
|
||||
- Qwen models
|
||||
- OpenWebUI
|
||||
- OpenHands
|
||||
- Claude Code-style workflows pointed at local models where possible
|
||||
- IDE assistants
|
||||
- Task/backlog-driven development agents
|
||||
|
||||
Important preference:
|
||||
|
||||
- Agents should work from clear task files, context files, and isolated environments.
|
||||
- Agents should not make broad uncontrolled changes.
|
||||
- Agents should be able to run in a VM, LXC, or Docker container depending on risk level.
|
||||
|
||||
## Recommended Isolation Model
|
||||
|
||||
For autonomous coding agents:
|
||||
|
||||
Preferred:
|
||||
|
||||
- Dedicated VM or LXC on Proxmox
|
||||
- Access only to required repositories
|
||||
- Limited credentials
|
||||
- Network access restricted where possible
|
||||
- Disposable working directories
|
||||
- Git-based review before merge
|
||||
|
||||
Avoid:
|
||||
|
||||
- Giving agents unrestricted access to the main development machine
|
||||
- Giving agents broad production credentials
|
||||
- Allowing agents to directly deploy without review
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
Repository Context
|
||||
|
||||
Git Server:
|
||||
|
||||
https://gitea.rdbcloud.co.uk
|
||||
|
||||
Repository:
|
||||
|
||||
rdb-discovery
|
||||
|
||||
Primary Workflow:
|
||||
|
||||
Feature Branch
|
||||
→ Commit
|
||||
→ Pull Request
|
||||
→ Merge
|
||||
|
||||
Branch Naming:
|
||||
|
||||
feature/TASK-001
|
||||
fix/TASK-001
|
||||
docs/TASK-001
|
||||
|
||||
Commit Format:
|
||||
|
||||
feat: add command
|
||||
fix: correct behaviour
|
||||
docs: update documentation
|
||||
test: add tests
|
||||
chore: project maintenance
|
||||
@@ -0,0 +1,22 @@
|
||||
[project]
|
||||
name = "rdb-discovery"
|
||||
version = "0.1.0"
|
||||
description = "Markdown-first discovery and delivery workflow CLI for software projects."
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"typer>=0.12.0",
|
||||
"rich>=13.0.0"
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"pytest>=8.0.0"
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
rdb = "rdb_discovery.cli:app"
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools>=68"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
@@ -0,0 +1,55 @@
|
||||
Metadata-Version: 2.4
|
||||
Name: rdb-discovery
|
||||
Version: 0.1.0
|
||||
Summary: Markdown-first discovery and delivery workflow CLI for software projects.
|
||||
Requires-Python: >=3.11
|
||||
Description-Content-Type: text/markdown
|
||||
Requires-Dist: typer>=0.12.0
|
||||
Requires-Dist: rich>=13.0.0
|
||||
Provides-Extra: dev
|
||||
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
||||
|
||||
# rdb-discovery
|
||||
|
||||
A small CLI-first tool for repeatable software project discovery and delivery.
|
||||
|
||||
It creates markdown files that help humans and AI coding agents understand:
|
||||
|
||||
- what is being built
|
||||
- why it exists
|
||||
- what questions remain open
|
||||
- what task should be done next
|
||||
- what stage the project is currently in
|
||||
|
||||
## Install for local development
|
||||
|
||||
```bash
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install -e '.[dev]'
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
rdb init
|
||||
rdb discover
|
||||
rdb status
|
||||
rdb next
|
||||
rdb start TASK-001
|
||||
rdb complete TASK-001
|
||||
rdb handoff
|
||||
```
|
||||
|
||||
## Bootstrap workflow
|
||||
|
||||
1. Run `rdb init`
|
||||
2. Run `rdb discover`
|
||||
3. Run `rdb status`
|
||||
4. Run `rdb next`
|
||||
5. Give the next task to Claude Code or Cline
|
||||
6. Commit after each completed task
|
||||
|
||||
## Principle
|
||||
|
||||
Markdown files are the source of truth. No database is required.
|
||||
@@ -0,0 +1,17 @@
|
||||
README.md
|
||||
pyproject.toml
|
||||
src/rdb_discovery/__init__.py
|
||||
src/rdb_discovery/cli.py
|
||||
src/rdb_discovery/discovery.py
|
||||
src/rdb_discovery/handoff.py
|
||||
src/rdb_discovery/status.py
|
||||
src/rdb_discovery/tasks.py
|
||||
src/rdb_discovery/templates.py
|
||||
src/rdb_discovery.egg-info/PKG-INFO
|
||||
src/rdb_discovery.egg-info/SOURCES.txt
|
||||
src/rdb_discovery.egg-info/dependency_links.txt
|
||||
src/rdb_discovery.egg-info/entry_points.txt
|
||||
src/rdb_discovery.egg-info/requires.txt
|
||||
src/rdb_discovery.egg-info/top_level.txt
|
||||
tests/test_tasks.py
|
||||
tests/test_templates.py
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
[console_scripts]
|
||||
rdb = rdb_discovery.cli:app
|
||||
@@ -0,0 +1,5 @@
|
||||
typer>=0.12.0
|
||||
rich>=13.0.0
|
||||
|
||||
[dev]
|
||||
pytest>=8.0.0
|
||||
@@ -0,0 +1 @@
|
||||
rdb_discovery
|
||||
@@ -0,0 +1 @@
|
||||
__version__ = "0.1.0"
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,133 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
import typer
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
|
||||
from .discovery import append_discovery_answer, core_questions
|
||||
from .handoff import build_handoff
|
||||
from .status import project_stage, task_counts
|
||||
from .tasks import get_next_task, update_task_status
|
||||
from .templates import CONTEXT_FILES, write_file_if_missing
|
||||
|
||||
app = typer.Typer(help="RDB discovery and delivery workflow CLI.")
|
||||
console = Console()
|
||||
|
||||
|
||||
def root_path() -> Path:
|
||||
return Path.cwd()
|
||||
|
||||
|
||||
def append_run_log(root: Path, event: str, task_id: str = "", notes: str = "") -> None:
|
||||
path = root / "RUN_LOG.md"
|
||||
if not path.exists():
|
||||
path.write_text("# RUN_LOG.md\n\n| Date | Event | Task | Notes |\n|---|---|---|---|\n", encoding="utf-8")
|
||||
line = f"| {datetime.now().isoformat(timespec='seconds')} | {event} | {task_id} | {notes} |\n"
|
||||
with path.open("a", encoding="utf-8") as handle:
|
||||
handle.write(line)
|
||||
|
||||
|
||||
@app.command()
|
||||
def init() -> None:
|
||||
"""Create the initial markdown project structure."""
|
||||
root = root_path()
|
||||
created: list[str] = []
|
||||
skipped: list[str] = []
|
||||
|
||||
for relative_path, content in CONTEXT_FILES.items():
|
||||
if write_file_if_missing(root, relative_path, content):
|
||||
created.append(relative_path)
|
||||
else:
|
||||
skipped.append(relative_path)
|
||||
|
||||
console.print("[bold green]Initialised rdb-discovery files.[/bold green]")
|
||||
if created:
|
||||
console.print("\nCreated:")
|
||||
for item in created:
|
||||
console.print(f"- {item}")
|
||||
if skipped:
|
||||
console.print("\nSkipped existing files:")
|
||||
for item in skipped:
|
||||
console.print(f"- {item}")
|
||||
|
||||
|
||||
@app.command()
|
||||
def discover() -> None:
|
||||
"""Ask the core discovery questions and append answers to the discovery ledger."""
|
||||
root = root_path()
|
||||
write_file_if_missing(root, "context/discovery-log.md", CONTEXT_FILES["context/discovery-log.md"])
|
||||
|
||||
for index, question in enumerate(core_questions(), start=1):
|
||||
qid = f"Q-{index:03d}"
|
||||
answer = typer.prompt(question)
|
||||
confidence = typer.prompt("Confidence?", default="Medium")
|
||||
follow_up = typer.prompt("Follow-up needed?", default="No")
|
||||
append_discovery_answer(root, qid, question, answer, confidence, follow_up)
|
||||
|
||||
append_run_log(root, "Discovery completed", notes="Core questions answered")
|
||||
console.print("[bold green]Discovery complete.[/bold green]")
|
||||
|
||||
|
||||
@app.command()
|
||||
def status() -> None:
|
||||
"""Show current project stage and task counts."""
|
||||
root = root_path()
|
||||
console.print(f"[bold]Project stage:[/bold] {project_stage(root)}")
|
||||
|
||||
counts = task_counts(root)
|
||||
table = Table(title="Task Counts")
|
||||
table.add_column("Status")
|
||||
table.add_column("Count")
|
||||
|
||||
if counts:
|
||||
for status_name, count in counts.items():
|
||||
table.add_row(status_name, str(count))
|
||||
else:
|
||||
table.add_row("None", "0")
|
||||
|
||||
console.print(table)
|
||||
|
||||
|
||||
@app.command(name="next")
|
||||
def next_task() -> None:
|
||||
"""Show the next Todo task."""
|
||||
task = get_next_task(root_path())
|
||||
if not task:
|
||||
console.print("[yellow]No Todo task found.[/yellow]")
|
||||
raise typer.Exit(code=0)
|
||||
|
||||
console.print(f"[bold]{task.task_id}[/bold] - {task.title}")
|
||||
console.print(f"Status: {task.status}")
|
||||
console.print(task.body)
|
||||
|
||||
|
||||
@app.command()
|
||||
def start(task_id: str) -> None:
|
||||
"""Mark a task as In Progress."""
|
||||
root = root_path()
|
||||
if not update_task_status(root, task_id, "In Progress"):
|
||||
console.print(f"[red]Task not found:[/red] {task_id}")
|
||||
raise typer.Exit(code=1)
|
||||
append_run_log(root, "Task started", task_id=task_id)
|
||||
console.print(f"[green]Started {task_id}.[/green]")
|
||||
|
||||
|
||||
@app.command()
|
||||
def complete(task_id: str) -> None:
|
||||
"""Mark a task as Done and record validation notes."""
|
||||
root = root_path()
|
||||
notes = typer.prompt("Validation notes", default="Not tested")
|
||||
if not update_task_status(root, task_id, "Done"):
|
||||
console.print(f"[red]Task not found:[/red] {task_id}")
|
||||
raise typer.Exit(code=1)
|
||||
append_run_log(root, "Task completed", task_id=task_id, notes=notes)
|
||||
console.print(f"[green]Completed {task_id}.[/green]")
|
||||
|
||||
|
||||
@app.command()
|
||||
def handoff() -> None:
|
||||
"""Print an AI-agent handoff summary."""
|
||||
console.print(build_handoff(root_path()))
|
||||
@@ -0,0 +1,38 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date
|
||||
from pathlib import Path
|
||||
|
||||
from .templates import CORE_QUESTIONS
|
||||
|
||||
|
||||
def append_discovery_answer(
|
||||
root: Path,
|
||||
question_id: str,
|
||||
question: str,
|
||||
answer: str,
|
||||
confidence: str,
|
||||
follow_up_needed: str,
|
||||
) -> None:
|
||||
log_path = root / "context" / "discovery-log.md"
|
||||
log_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
if not log_path.exists():
|
||||
log_path.write_text(
|
||||
"# Discovery Log\n\n"
|
||||
"| ID | Question | Answer | Confidence | Follow-up needed | Linked decision | Linked task | Date |\n"
|
||||
"|---|---|---|---|---|---|---|---|\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
safe_answer = answer.replace("|", "\\|").replace("\n", " ").strip()
|
||||
line = (
|
||||
f"| {question_id} | {question} | {safe_answer} | {confidence} | "
|
||||
f"{follow_up_needed} | | | {date.today().isoformat()} |\n"
|
||||
)
|
||||
with log_path.open("a", encoding="utf-8") as handle:
|
||||
handle.write(line)
|
||||
|
||||
|
||||
def core_questions() -> list[str]:
|
||||
return CORE_QUESTIONS
|
||||
@@ -0,0 +1,45 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from .status import project_stage, task_counts
|
||||
from .tasks import get_next_task
|
||||
|
||||
|
||||
def build_handoff(root: Path) -> str:
|
||||
next_task = get_next_task(root)
|
||||
counts = task_counts(root)
|
||||
lines = [
|
||||
"# AI Agent Handoff",
|
||||
"",
|
||||
f"Project stage: {project_stage(root)}",
|
||||
"",
|
||||
"## Task Counts",
|
||||
]
|
||||
if counts:
|
||||
for status, count in counts.items():
|
||||
lines.append(f"- {status}: {count}")
|
||||
else:
|
||||
lines.append("- No tasks found")
|
||||
|
||||
lines.extend(["", "## Next Task"])
|
||||
if next_task:
|
||||
lines.extend([
|
||||
f"- ID: {next_task.task_id}",
|
||||
f"- Title: {next_task.title}",
|
||||
f"- Status: {next_task.status}",
|
||||
])
|
||||
else:
|
||||
lines.append("No Todo task found.")
|
||||
|
||||
lines.extend([
|
||||
"",
|
||||
"## Agent Rules",
|
||||
"- Implement one task only.",
|
||||
"- Make the smallest useful change possible.",
|
||||
"- Do not rewrite unrelated code.",
|
||||
"- Run relevant tests.",
|
||||
"- Update documentation if behaviour changes.",
|
||||
"- Report files changed, validation, risks, and next recommended task.",
|
||||
])
|
||||
return "\n".join(lines) + "\n"
|
||||
@@ -0,0 +1,25 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from .tasks import read_tasks
|
||||
|
||||
|
||||
def project_stage(root: Path) -> str:
|
||||
if not (root / "context" / "discovery-log.md").exists():
|
||||
return "NOT_INITIALISED"
|
||||
tasks = read_tasks(root)
|
||||
if not tasks:
|
||||
return "DISCOVERY"
|
||||
if any(task.status.lower() == "in progress" for task in tasks):
|
||||
return "BUILDING"
|
||||
if any(task.status.lower() == "todo" for task in tasks):
|
||||
return "TASKS_READY"
|
||||
return "REVIEW_READY"
|
||||
|
||||
|
||||
def task_counts(root: Path) -> dict[str, int]:
|
||||
counts: dict[str, int] = {}
|
||||
for task in read_tasks(root):
|
||||
counts[task.status] = counts.get(task.status, 0) + 1
|
||||
return counts
|
||||
@@ -0,0 +1,71 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
TASK_HEADING_RE = re.compile(r"^##\s+(TASK-\d+)\s+-\s+(.+)$", re.MULTILINE)
|
||||
STATUS_RE = re.compile(r"^Status:\s*(.+)$", re.MULTILINE)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Task:
|
||||
task_id: str
|
||||
title: str
|
||||
status: str
|
||||
body: str
|
||||
|
||||
|
||||
def read_tasks(root: Path) -> list[Task]:
|
||||
tasks_path = root / "TASKS.md"
|
||||
if not tasks_path.exists():
|
||||
return []
|
||||
|
||||
text = tasks_path.read_text(encoding="utf-8")
|
||||
matches = list(TASK_HEADING_RE.finditer(text))
|
||||
tasks: list[Task] = []
|
||||
|
||||
for index, match in enumerate(matches):
|
||||
start = match.start()
|
||||
end = matches[index + 1].start() if index + 1 < len(matches) else len(text)
|
||||
block = text[start:end]
|
||||
status_match = STATUS_RE.search(block)
|
||||
status = status_match.group(1).strip() if status_match else "Unknown"
|
||||
tasks.append(Task(match.group(1), match.group(2).strip(), status, block))
|
||||
|
||||
return tasks
|
||||
|
||||
|
||||
def get_next_task(root: Path) -> Task | None:
|
||||
for task in read_tasks(root):
|
||||
if task.status.lower() == "todo":
|
||||
return task
|
||||
return None
|
||||
|
||||
|
||||
def update_task_status(root: Path, task_id: str, new_status: str) -> bool:
|
||||
tasks_path = root / "TASKS.md"
|
||||
if not tasks_path.exists():
|
||||
return False
|
||||
|
||||
text = tasks_path.read_text(encoding="utf-8")
|
||||
matches = list(TASK_HEADING_RE.finditer(text))
|
||||
|
||||
for index, match in enumerate(matches):
|
||||
if match.group(1) != task_id:
|
||||
continue
|
||||
|
||||
start = match.start()
|
||||
end = matches[index + 1].start() if index + 1 < len(matches) else len(text)
|
||||
block = text[start:end]
|
||||
if STATUS_RE.search(block):
|
||||
new_block = STATUS_RE.sub(f"Status: {new_status}", block, count=1)
|
||||
else:
|
||||
lines = block.splitlines()
|
||||
lines.insert(1, f"Status: {new_status}")
|
||||
new_block = "\n".join(lines) + "\n"
|
||||
|
||||
tasks_path.write_text(text[:start] + new_block + text[end:], encoding="utf-8")
|
||||
return True
|
||||
|
||||
return False
|
||||
@@ -0,0 +1,155 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
CORE_QUESTIONS = [
|
||||
"What problem are we solving?",
|
||||
"Who is the user?",
|
||||
"What does success look like?",
|
||||
"What is the minimum useful version?",
|
||||
"What data do we need?",
|
||||
"What systems must it connect to?",
|
||||
"What are the risks?",
|
||||
"What must not happen?",
|
||||
"How will we test it?",
|
||||
"How will it be deployed?",
|
||||
]
|
||||
|
||||
CONTEXT_FILES: dict[str, str] = {
|
||||
"context/discovery-log.md": """# Discovery Log
|
||||
|
||||
| ID | Question | Answer | Confidence | Follow-up needed | Linked decision | Linked task | Date |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
""",
|
||||
"context/product-brief.md": """# Product Brief
|
||||
|
||||
## Problem
|
||||
|
||||
TBD
|
||||
|
||||
## Users
|
||||
|
||||
TBD
|
||||
|
||||
## Success Criteria
|
||||
|
||||
TBD
|
||||
|
||||
## Minimum Useful Version
|
||||
|
||||
TBD
|
||||
""",
|
||||
"context/architecture.md": """# Architecture
|
||||
|
||||
## Overview
|
||||
|
||||
TBD
|
||||
|
||||
## Components
|
||||
|
||||
TBD
|
||||
|
||||
## Integrations
|
||||
|
||||
TBD
|
||||
|
||||
## Deployment
|
||||
|
||||
TBD
|
||||
""",
|
||||
"context/decisions.md": """# Decisions
|
||||
|
||||
| ID | Decision | Reason | Date |
|
||||
|---|---|---|---|
|
||||
""",
|
||||
"context/risks.md": """# Risks
|
||||
|
||||
| ID | Risk | Impact | Mitigation | Status |
|
||||
|---|---|---|---|---|
|
||||
""",
|
||||
"context/assumptions.md": """# Assumptions
|
||||
|
||||
| ID | Assumption | Confidence | Validation Needed |
|
||||
|---|---|---|---|
|
||||
""",
|
||||
"context/open-questions.md": """# Open Questions
|
||||
|
||||
| ID | Question | Reason | Owner | Status |
|
||||
|---|---|---|---|---|
|
||||
""",
|
||||
"TASKS.md": """# TASKS.md
|
||||
|
||||
## TASK-001 - Create Python CLI project skeleton
|
||||
Status: Done
|
||||
|
||||
Goal: Create the initial package structure, CLI entry point, and markdown-first bootstrap.
|
||||
|
||||
Acceptance Criteria:
|
||||
- `rdb --help` runs
|
||||
- `rdb init` creates project files
|
||||
- README exists
|
||||
|
||||
## TASK-002 - Run initial project discovery
|
||||
Status: Todo
|
||||
|
||||
Goal: Run `rdb discover` and capture the core project answers.
|
||||
|
||||
Acceptance Criteria:
|
||||
- all 10 core questions are answered
|
||||
- discovery-log.md contains ledger entries
|
||||
- low-confidence answers are marked for follow-up
|
||||
|
||||
## TASK-003 - Review generated context files
|
||||
Status: Todo
|
||||
|
||||
Goal: Review the generated markdown files and fill in obvious gaps.
|
||||
|
||||
Acceptance Criteria:
|
||||
- product-brief.md reviewed
|
||||
- architecture.md reviewed
|
||||
- open-questions.md updated
|
||||
|
||||
## TASK-004 - Implement ask-more command
|
||||
Status: Todo
|
||||
|
||||
Goal: Add a command that finds weak answers and asks deeper follow-up questions.
|
||||
|
||||
Acceptance Criteria:
|
||||
- command reads discovery-log.md
|
||||
- low-confidence answers are detected
|
||||
- follow-up answers are appended to discovery-log.md
|
||||
""",
|
||||
"TEST_PLAN.md": """# TEST_PLAN.md
|
||||
|
||||
## Manual Tests
|
||||
|
||||
| ID | Test | Expected Result | Status |
|
||||
|---|---|---|---|
|
||||
| TEST-001 | Run `rdb --help` | CLI help is displayed | Not run |
|
||||
| TEST-002 | Run `rdb init` | Markdown files are created | Not run |
|
||||
| TEST-003 | Run `rdb status` | Project status is displayed | Not run |
|
||||
| TEST-004 | Run `rdb next` | Next Todo task is shown | Not run |
|
||||
|
||||
## Automated Tests
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
pytest
|
||||
```
|
||||
""",
|
||||
"RUN_LOG.md": """# RUN_LOG.md
|
||||
|
||||
| Date | Event | Task | Notes |
|
||||
|---|---|---|---|
|
||||
""",
|
||||
}
|
||||
|
||||
|
||||
def write_file_if_missing(root: Path, relative_path: str, content: str) -> bool:
|
||||
target = root / relative_path
|
||||
if target.exists():
|
||||
return False
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
target.write_text(content, encoding="utf-8")
|
||||
return True
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,29 @@
|
||||
from pathlib import Path
|
||||
|
||||
from rdb_discovery.tasks import get_next_task, update_task_status
|
||||
|
||||
|
||||
def test_get_next_task(tmp_path: Path) -> None:
|
||||
(tmp_path / "TASKS.md").write_text(
|
||||
"# TASKS.md\n\n"
|
||||
"## TASK-001 - First\nStatus: Done\n\n"
|
||||
"## TASK-002 - Second\nStatus: Todo\n\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
task = get_next_task(tmp_path)
|
||||
|
||||
assert task is not None
|
||||
assert task.task_id == "TASK-002"
|
||||
assert task.title == "Second"
|
||||
|
||||
|
||||
def test_update_task_status(tmp_path: Path) -> None:
|
||||
tasks = tmp_path / "TASKS.md"
|
||||
tasks.write_text(
|
||||
"# TASKS.md\n\n## TASK-001 - First\nStatus: Todo\n\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
assert update_task_status(tmp_path, "TASK-001", "In Progress") is True
|
||||
assert "Status: In Progress" in tasks.read_text(encoding="utf-8")
|
||||
@@ -0,0 +1,10 @@
|
||||
from pathlib import Path
|
||||
|
||||
from rdb_discovery.templates import write_file_if_missing
|
||||
|
||||
|
||||
def test_write_file_if_missing(tmp_path: Path) -> None:
|
||||
assert write_file_if_missing(tmp_path, "context/test.md", "hello") is True
|
||||
assert (tmp_path / "context" / "test.md").read_text(encoding="utf-8") == "hello"
|
||||
assert write_file_if_missing(tmp_path, "context/test.md", "changed") is False
|
||||
assert (tmp_path / "context" / "test.md").read_text(encoding="utf-8") == "hello"
|
||||
Reference in New Issue
Block a user