commit dede6ecc60302cf78459466d42367fa3348f1181 Author: robbond Date: Mon Jun 1 17:43:02 2026 +0100 chore: bootstrap rdb-discovery diff --git a/.rdb/project.json b/.rdb/project.json new file mode 100644 index 0000000..a7e3586 --- /dev/null +++ b/.rdb/project.json @@ -0,0 +1,6 @@ +{ + "project_name": "rdb-discovery", + "stage": "DISCOVERY", + "current_task": "TASK-000", + "next_task": "TASK-001" +} diff --git a/AGENT_HANDOFF.md b/AGENT_HANDOFF.md new file mode 100644 index 0000000..83d848c --- /dev/null +++ b/AGENT_HANDOFF.md @@ -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 diff --git a/PROJECT_STATE.md b/PROJECT_STATE.md new file mode 100644 index 0000000..f83bd5c --- /dev/null +++ b/PROJECT_STATE.md @@ -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 diff --git a/README.md b/README.md new file mode 100644 index 0000000..6d517e0 --- /dev/null +++ b/README.md @@ -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. diff --git a/RUN_LOG.md b/RUN_LOG.md new file mode 100644 index 0000000..bc2db45 --- /dev/null +++ b/RUN_LOG.md @@ -0,0 +1,4 @@ + +Run Log +2026-06-01 +Bootstrap project structure created. diff --git a/TASKS.md b/TASKS.md new file mode 100644 index 0000000..f3b6318 --- /dev/null +++ b/TASKS.md @@ -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. diff --git a/TEST_PLAN.md b/TEST_PLAN.md new file mode 100644 index 0000000..fbb813f --- /dev/null +++ b/TEST_PLAN.md @@ -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 diff --git a/context/agent-guidelines.md b/context/agent-guidelines.md new file mode 100644 index 0000000..93c59db --- /dev/null +++ b/context/agent-guidelines.md @@ -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. diff --git a/context/architecture.md b/context/architecture.md new file mode 100644 index 0000000..e69de29 diff --git a/context/assumptions.md b/context/assumptions.md new file mode 100644 index 0000000..e69de29 diff --git a/context/company-context.md b/context/company-context.md new file mode 100644 index 0000000..8eba74e --- /dev/null +++ b/context/company-context.md @@ -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. diff --git a/context/current-environment.md b/context/current-environment.md new file mode 100644 index 0000000..b495c97 --- /dev/null +++ b/context/current-environment.md @@ -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: + +- + +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: +``` + +--- + +# Physical Infrastructure + +## Proxmox Host + +Hostname: + +- proxmox01 + +Purpose: + +- Primary virtualisation host + +Hardware: + +CPU: + +- + +RAM: + +- 16 GB + +Storage: + +-
+ +Network: + +- + +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 +- + +Endpoints: + +```text +http://: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: + +- +- 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: + +- + +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: + +- + +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. + +--- + +# 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 diff --git a/context/decisions.md b/context/decisions.md new file mode 100644 index 0000000..e69de29 diff --git a/context/development-context.md b/context/development-context.md new file mode 100644 index 0000000..27bbabb --- /dev/null +++ b/context/development-context.md @@ -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 diff --git a/context/discovery-log.md b/context/discovery-log.md new file mode 100644 index 0000000..e69de29 diff --git a/context/infrastructure-context.md b/context/infrastructure-context.md new file mode 100644 index 0000000..3453024 --- /dev/null +++ b/context/infrastructure-context.md @@ -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 diff --git a/context/open-questions.md b/context/open-questions.md new file mode 100644 index 0000000..e69de29 diff --git a/context/product-brief.md b/context/product-brief.md new file mode 100644 index 0000000..e69de29 diff --git a/context/repository-context.md b/context/repository-context.md new file mode 100644 index 0000000..da72488 --- /dev/null +++ b/context/repository-context.md @@ -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 diff --git a/context/risks.md b/context/risks.md new file mode 100644 index 0000000..e69de29 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..b003935 --- /dev/null +++ b/pyproject.toml @@ -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" diff --git a/src/rdb_discovery.egg-info/PKG-INFO b/src/rdb_discovery.egg-info/PKG-INFO new file mode 100644 index 0000000..250f67b --- /dev/null +++ b/src/rdb_discovery.egg-info/PKG-INFO @@ -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. diff --git a/src/rdb_discovery.egg-info/SOURCES.txt b/src/rdb_discovery.egg-info/SOURCES.txt new file mode 100644 index 0000000..fda3f8b --- /dev/null +++ b/src/rdb_discovery.egg-info/SOURCES.txt @@ -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 \ No newline at end of file diff --git a/src/rdb_discovery.egg-info/dependency_links.txt b/src/rdb_discovery.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/rdb_discovery.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/src/rdb_discovery.egg-info/entry_points.txt b/src/rdb_discovery.egg-info/entry_points.txt new file mode 100644 index 0000000..37165c3 --- /dev/null +++ b/src/rdb_discovery.egg-info/entry_points.txt @@ -0,0 +1,2 @@ +[console_scripts] +rdb = rdb_discovery.cli:app diff --git a/src/rdb_discovery.egg-info/requires.txt b/src/rdb_discovery.egg-info/requires.txt new file mode 100644 index 0000000..fc3d545 --- /dev/null +++ b/src/rdb_discovery.egg-info/requires.txt @@ -0,0 +1,5 @@ +typer>=0.12.0 +rich>=13.0.0 + +[dev] +pytest>=8.0.0 diff --git a/src/rdb_discovery.egg-info/top_level.txt b/src/rdb_discovery.egg-info/top_level.txt new file mode 100644 index 0000000..8f562da --- /dev/null +++ b/src/rdb_discovery.egg-info/top_level.txt @@ -0,0 +1 @@ +rdb_discovery diff --git a/src/rdb_discovery/__init__.py b/src/rdb_discovery/__init__.py new file mode 100644 index 0000000..3dc1f76 --- /dev/null +++ b/src/rdb_discovery/__init__.py @@ -0,0 +1 @@ +__version__ = "0.1.0" diff --git a/src/rdb_discovery/__pycache__/__init__.cpython-314.pyc b/src/rdb_discovery/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000..a43f72e Binary files /dev/null and b/src/rdb_discovery/__pycache__/__init__.cpython-314.pyc differ diff --git a/src/rdb_discovery/__pycache__/cli.cpython-314.pyc b/src/rdb_discovery/__pycache__/cli.cpython-314.pyc new file mode 100644 index 0000000..87455b2 Binary files /dev/null and b/src/rdb_discovery/__pycache__/cli.cpython-314.pyc differ diff --git a/src/rdb_discovery/__pycache__/discovery.cpython-314.pyc b/src/rdb_discovery/__pycache__/discovery.cpython-314.pyc new file mode 100644 index 0000000..6d97dd1 Binary files /dev/null and b/src/rdb_discovery/__pycache__/discovery.cpython-314.pyc differ diff --git a/src/rdb_discovery/__pycache__/handoff.cpython-314.pyc b/src/rdb_discovery/__pycache__/handoff.cpython-314.pyc new file mode 100644 index 0000000..c3cbe2e Binary files /dev/null and b/src/rdb_discovery/__pycache__/handoff.cpython-314.pyc differ diff --git a/src/rdb_discovery/__pycache__/status.cpython-314.pyc b/src/rdb_discovery/__pycache__/status.cpython-314.pyc new file mode 100644 index 0000000..31fa705 Binary files /dev/null and b/src/rdb_discovery/__pycache__/status.cpython-314.pyc differ diff --git a/src/rdb_discovery/__pycache__/tasks.cpython-314.pyc b/src/rdb_discovery/__pycache__/tasks.cpython-314.pyc new file mode 100644 index 0000000..2c02edd Binary files /dev/null and b/src/rdb_discovery/__pycache__/tasks.cpython-314.pyc differ diff --git a/src/rdb_discovery/__pycache__/templates.cpython-314.pyc b/src/rdb_discovery/__pycache__/templates.cpython-314.pyc new file mode 100644 index 0000000..f2d8a6a Binary files /dev/null and b/src/rdb_discovery/__pycache__/templates.cpython-314.pyc differ diff --git a/src/rdb_discovery/cli.py b/src/rdb_discovery/cli.py new file mode 100644 index 0000000..b53f05c --- /dev/null +++ b/src/rdb_discovery/cli.py @@ -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())) diff --git a/src/rdb_discovery/discovery.py b/src/rdb_discovery/discovery.py new file mode 100644 index 0000000..3ead654 --- /dev/null +++ b/src/rdb_discovery/discovery.py @@ -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 diff --git a/src/rdb_discovery/handoff.py b/src/rdb_discovery/handoff.py new file mode 100644 index 0000000..aa1560c --- /dev/null +++ b/src/rdb_discovery/handoff.py @@ -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" diff --git a/src/rdb_discovery/status.py b/src/rdb_discovery/status.py new file mode 100644 index 0000000..b66c802 --- /dev/null +++ b/src/rdb_discovery/status.py @@ -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 diff --git a/src/rdb_discovery/tasks.py b/src/rdb_discovery/tasks.py new file mode 100644 index 0000000..02faa78 --- /dev/null +++ b/src/rdb_discovery/tasks.py @@ -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 diff --git a/src/rdb_discovery/templates.py b/src/rdb_discovery/templates.py new file mode 100644 index 0000000..3becffd --- /dev/null +++ b/src/rdb_discovery/templates.py @@ -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 diff --git a/tests/__pycache__/test_tasks.cpython-314-pytest-9.0.3.pyc b/tests/__pycache__/test_tasks.cpython-314-pytest-9.0.3.pyc new file mode 100644 index 0000000..aa16ed3 Binary files /dev/null and b/tests/__pycache__/test_tasks.cpython-314-pytest-9.0.3.pyc differ diff --git a/tests/__pycache__/test_templates.cpython-314-pytest-9.0.3.pyc b/tests/__pycache__/test_templates.cpython-314-pytest-9.0.3.pyc new file mode 100644 index 0000000..0436a15 Binary files /dev/null and b/tests/__pycache__/test_templates.cpython-314-pytest-9.0.3.pyc differ diff --git a/tests/test_tasks.py b/tests/test_tasks.py new file mode 100644 index 0000000..b0ba5bd --- /dev/null +++ b/tests/test_tasks.py @@ -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") diff --git a/tests/test_templates.py b/tests/test_templates.py new file mode 100644 index 0000000..c203dd1 --- /dev/null +++ b/tests/test_templates.py @@ -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"