Skip to content

Commit 3f1b1be

Browse files
authored
Refactor architecture guardrails derivation into ai-code-file (#363)
* Move guardrails to ai-code-file and add menu * tweak menu items * Bind Derive Architecture to A and update tests * bump version
1 parent ccb2219 commit 3f1b1be

7 files changed

Lines changed: 288 additions & 235 deletions

File tree

HISTORY.org

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@
33

44
** Main branch change
55

6+
** 1.81
7+
- Add architecture guardrails derivation command for existing repos
8+
- Include selected region in Emacs runtime debug prompts
9+
- Add repo-level DDD context derivation command and menu entry
10+
- Add MVP AI session dashboard with shared session registry
11+
- Add AI session checkpoint command to Other Tools menu
12+
613
** 1.80
714
- Improve Ghostel terminal integration
815
- Fix vterm resize rendering for AI sessions, by cjf-666

ai-code-discussion.el

Lines changed: 0 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -679,107 +679,6 @@ This value is used by `ai-code-take-notes' when suggesting where to store notes.
679679
"Content of the most recent AI output"
680680
"Default request text for `ai-code-take-notes'.")
681681

682-
(defconst ai-code-discussion--architecture-guardrails-file-name
683-
"guardrails.org"
684-
"File name for derived architecture guardrails.")
685-
686-
(defconst ai-code-discussion--architecture-guardrails-directory-name
687-
"architecture"
688-
"Directory name for derived architecture guardrails.")
689-
690-
(defconst ai-code-discussion--architecture-guardrails-template
691-
(mapconcat #'identity
692-
'("#+TITLE: Architecture Guardrails"
693-
""
694-
"* Purpose"
695-
""
696-
"* Important Modules / Areas"
697-
""
698-
"* Dependency Rules"
699-
""
700-
"* State and Ownership Rules"
701-
""
702-
"* AI Change Rules"
703-
""
704-
"* Required Validation"
705-
""
706-
"* Notes and Uncertainties"
707-
"")
708-
"\n")
709-
"Initial Org template for architecture guardrails.")
710-
711-
(defun ai-code--architecture-guardrails-relative-path ()
712-
"Return the repo-relative path for the architecture guardrails file."
713-
(concat ai-code-files-dir-name "/"
714-
ai-code-discussion--architecture-guardrails-directory-name "/"
715-
ai-code-discussion--architecture-guardrails-file-name))
716-
717-
(defun ai-code--architecture-guardrails-file-path ()
718-
"Return the absolute path for the architecture guardrails file."
719-
(expand-file-name ai-code-discussion--architecture-guardrails-file-name
720-
(expand-file-name
721-
ai-code-discussion--architecture-guardrails-directory-name
722-
(ai-code--ensure-files-directory))))
723-
724-
(defun ai-code--ensure-architecture-guardrails-file ()
725-
"Create the architecture guardrails file with a starter template if missing."
726-
(let ((target-file (ai-code--architecture-guardrails-file-path)))
727-
(unless (file-directory-p (file-name-directory target-file))
728-
(make-directory (file-name-directory target-file) t))
729-
(unless (file-exists-p target-file)
730-
(with-temp-file target-file
731-
(insert ai-code-discussion--architecture-guardrails-template)))
732-
target-file))
733-
734-
(defun ai-code--build-architecture-guardrails-prompt (git-root)
735-
"Build the default prompt to derive architecture guardrails for GIT-ROOT."
736-
(let ((relative-path (ai-code--architecture-guardrails-relative-path)))
737-
(mapconcat
738-
#'identity
739-
(list "Derive a lightweight architecture guardrails document for this existing repository."
740-
(format "Repository path: %s" git-root)
741-
(format "Write or update @%s in Org-mode format." relative-path)
742-
""
743-
"Infer practical module boundaries, dependency rules, state ownership rules, and validation expectations from the current code, tests, docs, and filenames."
744-
"Do not invent an ideal architecture."
745-
"Do not force DDD, Hexagonal Architecture, or Clean Architecture onto the repository."
746-
"Prefer simple, practical rules over abstract architecture theory."
747-
"Mark uncertain conclusions clearly."
748-
"Focus on what helps future AI coding sessions avoid breaking boundaries or introducing messy dependencies."
749-
"Do not suggest large refactors unless clearly separated as optional future ideas."
750-
"Keep it concise, practical, and small enough to reuse in future AI prompts."
751-
""
752-
"Use this Org structure:"
753-
"#+TITLE: Architecture Guardrails"
754-
""
755-
"* Purpose"
756-
"* Important Modules / Areas"
757-
"* Dependency Rules"
758-
"* State and Ownership Rules"
759-
"* AI Change Rules"
760-
"* Required Validation"
761-
"* Notes and Uncertainties"
762-
""
763-
"If the file already exists, refine it instead of rewriting unrelated guidance.")
764-
"\n")))
765-
766-
;;;###autoload
767-
(defun ai-code-derive-architecture-guardrails ()
768-
"Ask the current AI backend to derive repository architecture guardrails."
769-
(interactive)
770-
(let ((git-root (ai-code--git-root)))
771-
(unless git-root
772-
(user-error "Not in a git repository"))
773-
(ai-code--ensure-architecture-guardrails-file)
774-
(if-let ((final-prompt
775-
(ai-code-read-string
776-
"Prompt: "
777-
(ai-code--build-architecture-guardrails-prompt git-root))))
778-
(progn
779-
(ai-code--insert-prompt final-prompt)
780-
(message "Requested architecture guardrails for %s" git-root))
781-
(message "Architecture guardrails request cancelled"))))
782-
783682
(defun ai-code--get-note-candidates (default-note-file)
784683
"Get a list of candidate note files.
785684
DEFAULT-NOTE-FILE is included in the list. Visible org buffers are prioritized."

ai-code-file.el

Lines changed: 104 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,35 @@ a Git repository or when `magit-toplevel' signals an error."
5959
".ai.code.files/architecture/domain-context.org"
6060
"Repository-relative path for the derived DDD context document.")
6161

62+
(defconst ai-code-file--architecture-guardrails-file-name
63+
"guardrails.org"
64+
"File name for derived architecture guardrails.")
65+
66+
(defconst ai-code-file--architecture-guardrails-directory-name
67+
"architecture"
68+
"Directory name for derived architecture guardrails.")
69+
70+
(defconst ai-code-file--architecture-guardrails-template
71+
(mapconcat #'identity
72+
'("#+TITLE: Architecture Guardrails"
73+
""
74+
"* Purpose"
75+
""
76+
"* Important Modules / Areas"
77+
""
78+
"* Dependency Rules"
79+
""
80+
"* State and Ownership Rules"
81+
""
82+
"* AI Change Rules"
83+
""
84+
"* Required Validation"
85+
""
86+
"* Notes and Uncertainties"
87+
"")
88+
"\n")
89+
"Initial Org template for architecture guardrails.")
90+
6291
(defun ai-code--resolve-auto-test-suffix-for-current-send ()
6392
"Return auto test suffix for this send action in file operations."
6493
(if (fboundp 'ai-code--resolve-auto-test-suffix-for-send)
@@ -647,9 +676,81 @@ Includes stored context entries for the current Git repository if available."
647676
"** Main Domain Concepts\n"
648677
"** Bounded Context Candidates\n"
649678
"** Core Flows\n"
650-
"** Domain Invariants / Business Rules\n"
651-
"** Testing Ideas\n"
652-
"** Notes and Uncertainties"))
679+
"** Domain Invariants / Business Rules\n"
680+
"** Testing Ideas\n"
681+
"** Notes and Uncertainties"))
682+
683+
(defun ai-code--architecture-guardrails-relative-path ()
684+
"Return the repo-relative path for the architecture guardrails file."
685+
(concat ai-code-files-dir-name "/"
686+
ai-code-file--architecture-guardrails-directory-name "/"
687+
ai-code-file--architecture-guardrails-file-name))
688+
689+
(defun ai-code--architecture-guardrails-file-path ()
690+
"Return the absolute path for the architecture guardrails file."
691+
(expand-file-name ai-code-file--architecture-guardrails-file-name
692+
(expand-file-name
693+
ai-code-file--architecture-guardrails-directory-name
694+
(ai-code--ensure-files-directory))))
695+
696+
(defun ai-code--ensure-architecture-guardrails-file ()
697+
"Create the architecture guardrails file with a starter template if missing."
698+
(let ((target-file (ai-code--architecture-guardrails-file-path)))
699+
(unless (file-directory-p (file-name-directory target-file))
700+
(make-directory (file-name-directory target-file) t))
701+
(unless (file-exists-p target-file)
702+
(with-temp-file target-file
703+
(insert ai-code-file--architecture-guardrails-template)))
704+
target-file))
705+
706+
(defun ai-code--build-architecture-guardrails-prompt (git-root)
707+
"Build the default prompt to derive architecture guardrails for GIT-ROOT."
708+
(let ((relative-path (ai-code--architecture-guardrails-relative-path)))
709+
(mapconcat
710+
#'identity
711+
(list "Derive a lightweight architecture guardrails document for this existing repository."
712+
(format "Repository path: %s" git-root)
713+
(format "Write or update @%s in Org-mode format." relative-path)
714+
""
715+
"Infer practical module boundaries, dependency rules, state ownership rules, and validation expectations from the current code, tests, docs, and filenames."
716+
"Do not invent an ideal architecture."
717+
"Do not force DDD, Hexagonal Architecture, or Clean Architecture onto the repository."
718+
"Prefer simple, practical rules over abstract architecture theory."
719+
"Mark uncertain conclusions clearly."
720+
"Focus on what helps future AI coding sessions avoid breaking boundaries or introducing messy dependencies."
721+
"Do not suggest large refactors unless clearly separated as optional future ideas."
722+
"Keep it concise, practical, and small enough to reuse in future AI prompts."
723+
""
724+
"Use this Org structure:"
725+
"#+TITLE: Architecture Guardrails"
726+
""
727+
"* Purpose"
728+
"* Important Modules / Areas"
729+
"* Dependency Rules"
730+
"* State and Ownership Rules"
731+
"* AI Change Rules"
732+
"* Required Validation"
733+
"* Notes and Uncertainties"
734+
""
735+
"If the file already exists, refine it instead of rewriting unrelated guidance.")
736+
"\n")))
737+
738+
;;;###autoload
739+
(defun ai-code-derive-architecture-guardrails ()
740+
"Ask the current AI backend to derive repository architecture guardrails."
741+
(interactive)
742+
(let ((git-root (ai-code--git-root)))
743+
(unless git-root
744+
(user-error "Not in a git repository"))
745+
(ai-code--ensure-architecture-guardrails-file)
746+
(if-let ((final-prompt
747+
(ai-code-read-string
748+
"Prompt: "
749+
(ai-code--build-architecture-guardrails-prompt git-root))))
750+
(progn
751+
(ai-code--insert-prompt final-prompt)
752+
(message "Requested architecture guardrails for %s" git-root))
753+
(message "Architecture guardrails request cancelled"))))
653754

654755
;;;###autoload
655756
(defun ai-code-derive-ddd-context ()

ai-code.el

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
;;; ai-code.el --- Unified interface for AI coding backends such as Codex CLI, Copilot CLI, Claude Code, Gemini CLI, Opencode, Kilo, Grok CLI, etc -*- lexical-binding: t; -*-
22

33
;; Author: Kang Tu <tninja@gmail.com>
4-
;; Version: 1.80
4+
;; Version: 1.81
55
;; Package-Requires: ((emacs "29.1") (transient "0.9.0") (magit "2.1.0"))
66
;; URL: https://github.com/tninja/ai-code-interface.el
77

@@ -418,6 +418,22 @@ Shows the current backend label to the right."
418418
(format "Select Terminal (%s)"
419419
(symbol-name ai-code-backends-infra-terminal-backend)))
420420

421+
(defconst ai-code--architecture-document-choices
422+
'(("Derive Architecture Guardrails" . ai-code-derive-architecture-guardrails)
423+
("Derive DDD Context for Repo" . ai-code-derive-ddd-context))
424+
"Choices for `ai-code-derive-architecture-document`.")
425+
426+
(defun ai-code-derive-architecture-document ()
427+
"Derive an architecture document by selecting one of the available options."
428+
(interactive)
429+
(let* ((default-choice (caar ai-code--architecture-document-choices))
430+
(choice (completing-read "Derive architecture document: "
431+
(mapcar #'car ai-code--architecture-document-choices)
432+
nil t nil nil default-choice))
433+
(command (alist-get choice ai-code--architecture-document-choices
434+
nil nil #'string=)))
435+
(funcall command)))
436+
421437
;; Mirror aider.el's reusable-section approach using `transient-define-group`.
422438
(transient-define-group ai-code--menu-ai-cli-session
423439
("a" "Start AI CLI (C-u: args)" ai-code-cli-start)
@@ -436,37 +452,37 @@ Shows the current backend label to the right."
436452
(ai-code--infix-toggle-suffix)
437453
("c" "Code change (C-u: clipboard)" ai-code-code-change)
438454
("i" "Implement TODO (C-u: clipboard)" ai-code-implement-todo)
439-
("o" "Derive DDD Context for Repo" ai-code-derive-ddd-context)
440455
("q" "Ask question (C-u: clipboard)" ai-code-ask-question)
441456
("x" "Explain code in scope" ai-code-explain)
442457
("<SPC>" "Send command (C-u: context)" ai-code-send-command)
443458
("@" "Context (add/show/clear)" ai-code-context-action)
444459
("C" "Create file or dir with AI" ai-code-create-file-or-dir)
460+
(":" "Speech to text input" ai-code-speech-to-text-input)
445461
("w" "New worktree branch (C-u: status)" ai-code-git-worktree-action))
446462

447463
(transient-define-group ai-code--menu-agile-development
448464
(ai-code--infix-select-code-change-auto-test)
449465
("r" "Refactor Code" ai-code-refactor-book-method)
450466
("t" "Test Driven Development" ai-code-tdd-cycle)
451467
("v" "GitHub PR AI Action" ai-code-pull-or-review-diff-file)
468+
;; DONE: Move ai-code-derive-architecture-guardrails ai-code-file.el. Add a new menu item: "Derive architecture document", bind to D. It let user choose from complet-reading: Derive Architecture Guardrails, and Derive DDD Context for Repo. No need to keep other two separate menu items
469+
("A" "Derive architecture document" ai-code-derive-architecture-document)
452470
("!" "Run Current File or Command" ai-code-run-current-file-or-shell-cmd)
453471
("b" "Build/Test/Lint (AI follow-up)" ai-code-build-or-test-project)
454472
("K" "Create/Open task file" ai-code-create-or-open-task-file)
455473
("/" "Search notes with AI" ai-code-search-notes-with-ai)
456-
("n" "Take notes from AI session" ai-code-take-notes)
457-
(":" "Speech to text input" ai-code-speech-to-text-input))
474+
("n" "Take notes from AI session" ai-code-take-notes))
458475

459476
(transient-define-group ai-code--menu-other-tools
460477
(ai-code--infix-toggle-auto-follow-up)
461478
("." "Init projectile and gtags" ai-code-init-project)
462479
("P" "AI session checkpoint" ai-code-session-checkpoint)
463480
("e" "Debug exception (C-u: clipboard)" ai-code-investigate-exception)
464481
("f" "Fix Flycheck errors in scope" ai-code-flycheck-fix-errors-in-scope)
465-
("A" "Derive Architecture Guardrails" ai-code-derive-architecture-guardrails)
466482
("k" "Copy Cur File Name (C-u: full)" ai-code-copy-buffer-file-name-to-clipboard)
467483
;; ("o" "Open recent file (C-u: insert)" ai-code-git-repo-recent-modified-files)
468484
("p" "Open prompt history file" ai-code-open-prompt-file)
469-
("m" "Debug python MCP server" ai-code-debug-mcp)
485+
;; ("m" "Debug python MCP server" ai-code-debug-mcp)
470486
;; ("N" "Toggle notifications" ai-code-notifications-toggle)
471487
("d" "Debug Emacs runtime" ai-code-debug-emacs-runtime)
472488
("|" "Apply prompt on file" ai-code-apply-prompt-on-current-file)

0 commit comments

Comments
 (0)