Commit 0aa91534837e
Changed files (2)
dots
config
pi
agent
extensions
path-validator
dots/config/ai/path-policies.json
@@ -1,19 +1,29 @@
{
"policies": [
{
- "name": "ai-sessions",
+ "name": "ai-sessions-location",
"description": "Session files should go to unified AI storage",
"filenamePattern": ".*session.*\\.md$",
"blockedPaths": [
"~/.config/claude/history/sessions/",
"~/.claude/history/sessions/"
],
- "suggestedPath": "~/.local/share/ai/sessions/",
+ "suggestedPath": "~/.local/share/ai/sessions/YYYY-MM/",
"action": "warn",
"enabled": true
},
{
- "name": "ai-plans",
+ "name": "ai-sessions-format",
+ "description": "Session files must follow YYYY-MM-DD-description.md format",
+ "pathPattern": ".*/ai/sessions/.*\\.md$",
+ "requiredFilenameFormat": "^\\d{4}-\\d{2}-\\d{2}-[a-z0-9-]+\\.md$",
+ "formatDescription": "YYYY-MM-DD-description.md (lowercase, hyphens only)",
+ "formatExample": "2026-02-05-unified-ai-storage.md",
+ "action": "block",
+ "enabled": true
+ },
+ {
+ "name": "ai-plans-location",
"description": "Plan files should go to unified AI storage",
"filenamePattern": ".*plan.*\\.md$",
"blockedPaths": [
@@ -25,27 +35,57 @@
"enabled": true
},
{
- "name": "ai-learnings",
+ "name": "ai-plans-format",
+ "description": "Plan files must follow kebab-case.md format",
+ "pathPattern": ".*/ai/plans/.*\\.md$",
+ "requiredFilenameFormat": "^[a-z0-9-]+\\.md$",
+ "formatDescription": "kebab-case.md (lowercase, hyphens, no dates)",
+ "formatExample": "unified-ai-storage-implementation.md",
+ "action": "block",
+ "enabled": true
+ },
+ {
+ "name": "ai-learnings-location",
"description": "Learning files should go to unified AI storage",
"filenamePattern": ".*learning.*\\.md$",
"blockedPaths": [
"~/.config/claude/history/learnings/"
],
- "suggestedPath": "~/.local/share/ai/learnings/",
+ "suggestedPath": "~/.local/share/ai/learnings/YYYY-MM/",
"action": "warn",
"enabled": true
},
{
- "name": "ai-research",
+ "name": "ai-learnings-format",
+ "description": "Learning files must follow YYYY-MM-DD-description.md format",
+ "pathPattern": ".*/ai/learnings/.*\\.md$",
+ "requiredFilenameFormat": "^\\d{4}-\\d{2}-\\d{2}-[a-z0-9-]+\\.md$",
+ "formatDescription": "YYYY-MM-DD-description.md (lowercase, hyphens only)",
+ "formatExample": "2026-02-05-debugging-timezone-issues.md",
+ "action": "block",
+ "enabled": true
+ },
+ {
+ "name": "ai-research-location",
"description": "Research files should go to unified AI storage",
"filenamePattern": ".*research.*\\.md$",
"blockedPaths": [
"~/.config/claude/history/research/"
],
- "suggestedPath": "~/.local/share/ai/research/",
+ "suggestedPath": "~/.local/share/ai/research/YYYY-MM/",
"action": "warn",
"enabled": true
},
+ {
+ "name": "ai-research-format",
+ "description": "Research files must follow YYYY-MM-DD-description.md format",
+ "pathPattern": ".*/ai/research/.*\\.md$",
+ "requiredFilenameFormat": "^\\d{4}-\\d{2}-\\d{2}-[a-z0-9-]+\\.md$",
+ "formatDescription": "YYYY-MM-DD-description.md (lowercase, hyphens only)",
+ "formatExample": "2026-02-05-chrono-node-evaluation.md",
+ "action": "block",
+ "enabled": true
+ },
{
"name": "no-secrets-in-repos",
"description": "Prevent writing secrets to git repositories",
dots/pi/agent/extensions/path-validator/index.ts
@@ -32,6 +32,12 @@ interface PathPolicy {
allowedPaths?: string[];
// Paths where this file type is blocked
blockedPaths?: string[];
+ // Required filename format (regex) - blocks if doesn't match
+ requiredFilenameFormat?: string;
+ // Human-readable description of required format
+ formatDescription?: string;
+ // Example of valid filename
+ formatExample?: string;
// Suggested correct path (for redirects)
suggestedPath?: string;
// Action: "warn" (default), "block", or "suggest"
@@ -220,6 +226,19 @@ export default function (pi: ExtensionAPI) {
});
}
}
+
+ // Check required filename format
+ if (policy.requiredFilenameFormat) {
+ const formatRegex = new RegExp(policy.requiredFilenameFormat);
+ if (!formatRegex.test(filename)) {
+ const formatDesc = policy.formatDescription || policy.requiredFilenameFormat;
+ const example = policy.formatExample ? ` (e.g., ${policy.formatExample})` : "";
+ violations.push({
+ policy,
+ reason: `Filename doesn't match required format: ${formatDesc}${example}`,
+ });
+ }
+ }
}
return {