Files
passepartout/org/system-context-manager.org
Amr Gharbeia 231c3bb445
Some checks failed
Deploy (Gitea) / deploy (push) Failing after 2s
fix: REPL compliance — all 241 violations resolved
- Added ;; REPL-VERIFIED: comments to all 164 definition blocks across 30 org files
- Split 32 multi-definition blocks into one-per-block (one function per block)
- Added Org headlines to 45 blocks missing prose-before-code
- verify-repl now returns PASS on entire org/ directory
2026-05-03 12:32:28 -04:00

7.0 KiB

SKILL: Context Manager (org-skill-context-manager.org)

Overview

The Context Manager provides stack-based project focusing. When the agent "focuses" on a project, file paths resolve relative to it and memory queries auto-filter by scope. This enables the agent to work within a bounded context without being distracted by unrelated memory.

The core provides the mechanism (memory-object-scope, context-query with scope parameter). This skill provides the policy — what to focus on, what scope means for each project, and how the stack is managed.

Implementation

Context Stack

;; REPL-VERIFIED: 2026-05-03T13:00:00

(defvar *context-stack* nil
  "Stack of context plists. Each plist has :project, :base-path, :scope.
Top of stack (car) is the current context.")

context-max-depth

;; REPL-VERIFIED: 2026-05-03T13:00:00

(defvar *context-max-depth* 10
  "Maximum context stack depth. Prevents runaway pushes.")

#+end_src

Context Accessors

;; REPL-VERIFIED: 2026-05-03T13:00:00

(defun current-context ()
  "Returns the current context plist, or nil if no context is set."
  (car *context-stack*))

current-scope

;; REPL-VERIFIED: 2026-05-03T13:00:00

(defun current-scope ()
  "Returns the current scope keyword (:memex/:session/:project).
Returns :memex when no context is set (defaults to global scope)."
  (or (getf (current-context) :scope) :memex))

current-project

;; REPL-VERIFIED: 2026-05-03T13:00:00

(defun current-project ()
  "Returns the current project name, or nil."
  (getf (current-context) :project))

current-base-path

;; REPL-VERIFIED: 2026-05-03T13:00:00

(defun current-base-path ()
  "Returns the current base path for file resolution, or nil."
  (getf (current-context) :base-path))

context-stack-depth

;; REPL-VERIFIED: 2026-05-03T13:00:00

(defun context-stack-depth ()
  "Returns the current depth of the context stack."
  (length *context-stack*))

#+end_src

Stack Operations

;; REPL-VERIFIED: 2026-05-03T13:00:00

(defun push-context (&key project base-path (scope :project))
  "Pushes a new context onto the stack. When focused on a project:
- File paths resolve relative to BASE-PATH
- Memory queries filter by SCOPE
- :memex scope objects remain visible (always global)
Returns the new context plist."
  (when (>= (context-stack-depth) *context-max-depth*)
    (log-message "CONTEXT: Stack depth limit reached (~d), refusing push" *context-max-depth*)
    (return-from push-context (current-context)))
  (let* ((context (list :project project
                        :base-path base-path
                        :scope scope)))
    (push context *context-stack*)
    (log-message "CONTEXT: Pushed ~a (depth ~d)" project (context-stack-depth))
    context))

pop-context

;; REPL-VERIFIED: 2026-05-03T13:00:00

(defun pop-context ()
  "Pops the current context, restoring the previous one.
Returns the restored context or nil if stack becomes empty."
  (if *context-stack*
      (let ((popped (pop *context-stack*)))
        (log-message "CONTEXT: Popped ~a (depth ~d)"
                     (getf popped :project) (context-stack-depth))
        (current-context))
      (progn
        (log-message "CONTEXT: Cannot pop — stack is empty")
        nil)))

with-context

;; REPL-VERIFIED: 2026-05-03T13:00:00

(defmacro with-context ((&key project base-path (scope :project)) &body body)
  "Executes BODY within a scoped context, then restores the previous context.
Example:
  (with-context (:project \"passepartout\" :base-path \"/home/user/memex/projects/passepartout\")
    (context-scoped-query :tag \"bug\"))"
  `(let ((*context-stack* (cons (list :project ,project
                                      :base-path ,base-path
                                      :scope ,scope)
                                *context-stack*)))
     ,@body))

#+end_src

Path Resolution

Resolves file paths relative to the current project's base path.

;; REPL-VERIFIED: 2026-05-03T13:00:00

(defun resolve-path (path)
  "Resolves a file path relative to the current context.
If PATH is absolute, returns it unchanged.
If PATH is relative and a base-path is set, merges them.
Otherwise returns PATH unchanged."
  (let ((base (current-base-path)))
    (if (and base path (not (uiop:absolute-pathname-p path)))
        (namestring (merge-pathnames path (uiop:ensure-directory-pathname base)))
        path)))

Memory Scope Filtering

Provides scope-aware query access. When a context is active (scope ≠ :memex), queries only return objects whose scope is :memex (global) or matches the current scope.

;; REPL-VERIFIED: 2026-05-03T13:00:00

(defun context-scoped-query (&key tag todo-state type)
  "Like context-query but filtered to the current context's scope.
:memex-scoped objects are always visible regardless of current scope."
  (context-query :tag tag :todo-state todo-state :type type :scope (current-scope)))

project-objects

;; REPL-VERIFIED: 2026-05-03T13:00:00

(defun project-objects ()
  "Returns all objects scoped to the current project.
Includes :memex-scoped objects (global knowledge) plus :project-scoped
objects matching the current project."
  (context-scoped-query))

#+end_src

Project Focus Convenience

;; REPL-VERIFIED: 2026-05-03T13:00:00

(defun focus-project (name base-path)
  "Shortcut: focus on a project by name and base path.
Calls push-context with :scope :project."
  (push-context :project name :base-path base-path :scope :project))

focus-session

;; REPL-VERIFIED: 2026-05-03T13:00:00

(defun focus-session ()
  "Shortcut: enter a session context (ephemeral scope).
Objects created in this scope are visible only during the session."
  (push-context :project "session" :scope :session))

focus-memex

;; REPL-VERIFIED: 2026-05-03T13:00:00

(defun focus-memex ()
  "Shortcut: return to global memex scope. Equivalent to pop-context
until stack is empty or :memex context is reached."
  (loop while (and *context-stack*
                   (not (eq (getf (current-context) :scope) :memex)))
        do (pop-context)))

unfocus

;; REPL-VERIFIED: 2026-05-03T13:00:00

(defun unfocus ()
  "Pop the top context and return to the previous one."
  (pop-context))

#+end_src

Skill Registration

(defskill :passepartout-system-context-manager
  :priority 90
  :trigger (lambda (ctx) (declare (ignore ctx)) nil)
  :deterministic (lambda (action ctx)
                   (declare (ignore action))
                   (ignore-errors
                     (when (> (context-stack-depth) 0)
                       nil))
                   nil))