A file-system-based, graph-oriented issue tracking library with hierarchical structure and pluggable storage backends.
Issues-FS stores issues as JSON files in .issues/ directories inside git repos, enabling version control with Git, offline access, and flexible deployment options. It provides the core data layer for building issue tracking applications -- both for human developers and AI agent workflows.
- File-Based Storage -- Issues stored as
issue.jsonfiles, easily version-controlled with Git - Graph-Oriented Model -- Issues, types, and links form a traversable graph via MGraph-DB integration
- Hierarchical Structure -- Nest issues inside other issues via
issues/subfolders (projects > versions > tasks > subtasks) - Pluggable Backends -- Works with memory, local disk, S3, SQLite, or ZIP via Memory-FS
- Type-Safe -- Built with
osbot-utilsType_Safe patterns for runtime validation - Recursive Discovery -- Find issues at any depth in the hierarchy
- Human-Readable -- Plain JSON files in a simple folder structure, inspectable with any text editor
pip install issues-fsFor command-line usage, also install the CLI:
pip install issues-fs-clifrom memory_fs.Memory_FS import Memory_FS
from memory_fs.storage_fs.Storage_FS__Memory import Storage_FS__Memory
from memory_fs.storage_fs.Storage_FS__Local_Disk import Storage_FS__Local_Disk
from issues_fs.issues.graph_services.Graph__Repository import Graph__Repository
from issues_fs.issues.graph_services.Node__Service import Node__Service
from issues_fs.issues.graph_services.Type__Service import Type__Service
from issues_fs.issues.storage.Path__Handler__Graph_Node import Path__Handler__Graph_Node
# Setup with in-memory storage (great for testing)
storage_fs = Storage_FS__Memory()
memory_fs = Memory_FS(storage_fs=storage_fs)
path_handler = Path__Handler__Graph_Node(base_path='')
repository = Graph__Repository(memory_fs=memory_fs, path_handler=path_handler)
# Or use local disk storage
storage_fs = Storage_FS__Local_Disk(root_path='.issues')
memory_fs = Memory_FS(storage_fs=storage_fs)
path_handler = Path__Handler__Graph_Node(base_path='')
repository = Graph__Repository(memory_fs=memory_fs, path_handler=path_handler)
# Initialize services
type_service = Type__Service(repository=repository)
node_service = Node__Service(repository=repository)
# Initialize default types
type_service.initialize_default_types()from issues_fs.schemas.graph.Schema__Node__Create__Request import Schema__Node__Create__Request
request = Schema__Node__Create__Request(
node_type = 'task',
title = 'Implement user authentication',
description = 'Add OAuth2 support',
status = 'backlog',
tags = ['security', 'backend']
)
response = node_service.create_node(request)
if response.success:
print(f"Created: {response.node.label}") # Task-1from issues_fs.schemas.safe_str.Safe_Str__Graph_Types import Safe_Str__Node_Type, Safe_Str__Node_Label
node = repository.node_load(
node_type = Safe_Str__Node_Type('task'),
label = Safe_Str__Node_Label('Task-1')
)
print(node.title) # "Implement user authentication"
print(node.status) # "backlog"# Find all issues, including nested ones
all_nodes = repository.nodes_list_all()
for info in all_nodes:
print(f"{info.label} ({info.node_type}) at {info.path}")
# Filter by root path
project_nodes = repository.nodes_list_all(
root_path=Safe_Str__File__Path('data/project/Project-1')
)# Load issue by folder path
node = repository.node_load_by_path(
Safe_Str__File__Path('data/project/Project-1/issues/Version-1/issues/Task-1')
)
# Find path for a label
path = repository.node_find_path_by_label(Safe_Str__Node_Label('Task-1'))from issues_fs.schemas.graph.Schema__Node__Update__Request import Schema__Node__Update__Request
request = Schema__Node__Update__Request(
status = 'in-progress',
tags = ['security', 'backend', 'urgent']
)
response = node_service.update_node(
node_type = Safe_Str__Node_Type('task'),
label = Safe_Str__Node_Label('Task-1'),
request = request
)response = node_service.delete_node(
node_type = Safe_Str__Node_Type('task'),
label = Safe_Str__Node_Label('Task-1')
)For efficient graph queries and visualization:
from issues_fs.mgraph.MGraph__Issues__Domain import MGraph__Issues__Domain
# Create sync service
from issues_fs.issues.graph_services.Graph__Repository__Factory import Graph__Repository__Factory
factory = Graph__Repository__Factory(root_path='.issues')
repository = factory.create_repository()
# Query the graph
sync_service = MGraph__Issues__Sync__Service(
repository = repository,
path_handler = path_handler
)
# Lazy load graph (syncs from filesystem)
graph = sync_service.ensure_loaded()
# Query by label
node = graph.get_node_by_label('Task-1')
# Get children
children = graph.get_children(node.node_id)
# Get ancestors (path to root)
ancestors = graph.get_ancestors(node.node_id)
# Force resync after external changes
sync_service.full_sync()The Issues-FS CLI provides command-line access to all operations:
# List all issues in the current repo
issues-fs list
# Create a new issue
issues-fs create --type task --title "Fix login bug"
# Show issue details
issues-fs show Task-1
# Update status
issues-fs update Task-1 --status in-progressInstall the CLI separately: pip install issues-fs-cli
Issues-FS uses a simple, human-readable folder structure:
.issues/
├── config/
│ ├── node-types.json # Issue type definitions
│ └── link-types.json # Link type definitions
├── data/
│ └── {type}/
│ └── {Label}/
│ ├── issue.json # Issue data
│ └── issues/ # Child issues
│ └── {Child-Label}/
│ └── issue.json
└── indexes/
└── issues.mgraph.json # MGraph-DB cache
.issues/
├── data/
│ └── project/
│ └── Project-1/
│ ├── issue.json
│ └── issues/
│ ├── Version-1/
│ │ ├── issue.json
│ │ └── issues/
│ │ ├── Task-1/
│ │ │ └── issue.json
│ │ └── Bug-2/
│ │ └── issue.json
│ └── Version-2/
│ └── issue.json
{
"node_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"node_type": "task",
"node_index": 1,
"label": "Task-1",
"title": "Implement user authentication",
"description": "Add OAuth2 support for user login",
"status": "in-progress",
"created_at": 1706745600000,
"updated_at": 1706832000000,
"tags": ["security", "backend"],
"links": [
{
"verb": "blocks",
"target_label": "Task-2"
}
],
"properties": {
"priority": "high",
"estimate": "3d"
}
}Default node types are created on initialization:
type_service.initialize_default_types()| Type | Display Name | Default Status |
|---|---|---|
git-repo |
Git Repo | active |
project |
Project | active |
version |
Version | planned |
task |
Task | backlog |
bug |
Bug | open |
feature |
Feature | backlog |
user-story |
User Story | backlog |
from issues_fs.schemas.graph.Schema__Node__Type import Schema__Node__Type
custom_type = Schema__Node__Type(
name = 'epic',
display_name = 'Epic',
color = '#9B59B6',
icon = 'rocket',
statuses = ['draft', 'active', 'completed'],
default_status = 'draft'
)
type_service.create_node_type(custom_type)┌──────────────────────────────────────────────────────────┐
│ Services │
│ Node__Service │ Type__Service │ Link__Service │
└───────────────────────────┬──────────────────────────────┘
│
┌───────────────────────────▼──────────────────────────────┐
│ Graph__Repository │
│ (Data access layer with Type_Safe) │
└───────────────────────────┬──────────────────────────────┘
│
┌───────────────────────────▼──────────────────────────────┐
│ Memory-FS │
│ Storage_FS__Memory │ Storage_FS__Local_Disk │ S3 │ … │
└──────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────┐
│ MGraph Integration │
│ MGraph__Issues__Sync__Service → MGraph__Issues__Domain │
└──────────────────────────────────────────────────────────┘
| Component | Purpose |
|---|---|
Graph__Repository |
Data access layer for nodes, types, indexes |
Graph__Repository__Factory |
Factory for creating configured repository instances |
Node__Service |
Business logic for CRUD operations |
Type__Service |
Manage node and link type definitions |
Link__Service |
Manage links between issues |
Comments__Service |
Manage comments on issues |
MGraph__Issues__Sync__Service |
Syncs filesystem to MGraph-DB |
MGraph__Issues__Domain |
Graph operations and indexes |
Path__Handler__Graph_Node |
Generate filesystem paths for graph nodes |
Path__Handler__Issues |
Generate filesystem paths for issue operations |
issues_fs/
├── issues/
│ ├── graph_services/ # Core services (Repository, Node, Type, Link, Comments)
│ ├── storage/ # Path handlers for filesystem operations
│ ├── phase_1/ # Root issue and children services
│ └── status/ # Issue status management
├── mgraph/ # MGraph-DB integration (domain model, sync, schemas)
├── schemas/ # Data models and type definitions
│ ├── graph/ # Graph node schemas (create, update, delete)
│ ├── issues/ # Issue-specific schemas
│ ├── identifiers/ # ID types and generators
│ ├── safe_str/ # Type-safe string primitives
│ ├── enums/ # Enumeration types
│ └── status/ # Status-related schemas
├── scripts/ # Utility scripts
├── utils/ # Version info and utilities
└── version/ # Package version management
This library is the core of a broader ecosystem coordinated through Issues-FS__Dev, which includes a CLI, web service, documentation, and a team of 10 AI agent roles that collaborate through Issues-FS itself.
| Repository | Description |
|---|---|
| Issues-FS | This repo -- core Python library |
| Issues-FS__CLI | Command-line interface |
| Issues-FS__Docs | Architecture documents, design briefs, specifications |
| Repository | Description |
|---|---|
| Issues-FS__Service | FastAPI web service |
| Issues-FS__Service__UI | Web UI |
| Issues-FS__Service__Client__Python | Python client for the service API |
| Repository | Description |
|---|---|
| Issues-FS__Dev | Parent orchestration repo for all submodules |
| Repository | Description |
|---|---|
| Issues-FS__Dev__Role__Dev | Dev agent -- implementation |
| Issues-FS__Dev__Role__Architect | Architect agent -- system design |
| Issues-FS__Dev__Role__QA | QA agent -- testing |
| Issues-FS__Dev__Role__AppSec | AppSec agent -- security |
| Issues-FS__Dev__Role__DevOps | DevOps agent -- CI/CD |
| Issues-FS__Dev__Role__Librarian | Librarian agent -- knowledge connectivity |
| Issues-FS__Dev__Role__Cartographer | Cartographer agent -- system mapping |
| Issues-FS__Dev__Role__Historian | Historian agent -- project narrative |
| Issues-FS__Dev__Role__Journalist | Journalist agent -- reporting |
| Issues-FS__Dev__Role__Conductor | Conductor agent -- orchestration |
| Repository | Description |
|---|---|
| Issues-FS__Dev__Human__Dinis_Cruz | Stakeholder repo for Dinis Cruz |
- Version: v0.4.5
- Tests: 475+ test methods across 36 test files
- Python: 3.12+
- Status: Actively developed
git clone https://github.com/owasp-sbot/Issues-FS.git
cd Issues-FS
pip install -e ".[dev]"pytestThis project follows the OSBot Python Formatting Guide:
- Type_Safe inheritance on all classes
- Safe_* primitives for type validation
@type_safedecorator on public methods- Aligned imports/parameters at column 70-80
- Explicit
is True/is Falsefor booleans
- Memory-FS -- Pluggable filesystem abstraction
- MGraph-DB -- Graph database operations
- OSBot-Utils -- Type_Safe utilities
- Git-native issue tracking -- Store issues alongside code, branch/merge with PRs
- Offline-first workflows -- Full functionality without network access
- Custom integrations -- Simple JSON format for easy tooling
- Hierarchical project management -- Organize epics > features > tasks > subtasks
- Embedded issue tracking -- Add issue tracking to any Python application
- AI agent collaboration -- Agents read and write issues as structured graph nodes
Apache License 2.0 -- see LICENSE for details.