Commit f9ccd73c06a6
Changed files (2)
dots
.config
claude
skills
Org
emacs
site-lisp
dots/.config/claude/skills/Org/SKILL.md
@@ -239,10 +239,15 @@ Productive day working on Claude skills.
- **Only create when explicitly asked** by the user
- Use the `journelly-claude-session` function via Emacs batch mode
- Format: Brief, factual, technical summaries of work accomplished
+- **Auto-tagging**: Tags are automatically detected and appended based on:
+ - File types changed (`.nix` → `#nixos`, `.el` → `#emacs`, `.go` → `#golang`)
+ - Git repository (`home` → `#homelab`, `tekton*` → `#tekton`)
+ - Keywords (`fix/bug` → `#debugging`, `feature/implement` → `#development`)
+ - Tools mentioned (`docker`, `kubernetes`, etc.)
- Examples:
- - "Fixed bug in authentication handler"
- - "Implemented feature X with tests"
- - "Refactored module Y for better performance"
+ - "Fixed bug in authentication handler" → auto-tagged with `#debugging`
+ - "Implemented feature X with tests" → auto-tagged with `#development #testing`
+ - "Refactored module Y for better performance" → auto-tagged with `#refactoring`
- **Never** write in first person or user's voice
- Keep entries concise (1-2 lines per timestamp)
dots/.config/emacs/site-lisp/journelly.el
@@ -18,9 +18,9 @@
;;
;; Entry formats:
;; - Regular: * [YYYY-MM-DD Day HH:MM] @ Location (hostname)
-;; - HH:MM :: entry content (appended entries)
+;; - HH:MM :: entry content #tags (appended entries, tags optional)
;; - Claude: * [YYYY-MM-DD Day HH:MM] @ Claude session
-;; - HH:MM :: session summary (automated only)
+;; - HH:MM :: session summary #auto-tagged (automated only)
;;
;; Usage:
;; (require 'journelly)
@@ -180,17 +180,227 @@ Creates today's entry if it doesn't exist, or appends to existing entry."
(save-buffer))
(message "Journal entry added"))
+(defun journelly--detect-tags (summary)
+ "Auto-detect tags for Claude session based on context and SUMMARY.
+Returns a list of tag strings (without # prefix)."
+ (let ((tags '()))
+
+ ;; Detect from file extensions (git status)
+ (when (file-exists-p ".git")
+ (let ((changed-files (shell-command-to-string "git status --short 2>/dev/null")))
+ (when (string-match-p "\\.nix" changed-files)
+ (push "nixos" tags))
+ (when (string-match-p "\\.go" changed-files)
+ (push "golang" tags))
+ (when (string-match-p "\\.el" changed-files)
+ (push "emacs" tags))
+ (when (string-match-p "\\.py" changed-files)
+ (push "python" tags))
+ (when (string-match-p "\\.rs" changed-files)
+ (push "rust" tags))
+ (when (string-match-p "Dockerfile\\|docker-compose" changed-files)
+ (push "docker" tags))
+ (when (string-match-p "\\.ya?ml" changed-files)
+ (push "kubernetes" tags))
+ (when (string-match-p "skills/" changed-files)
+ (push "claude-skills" tags))))
+
+ ;; Detect from git repository name
+ (when (file-exists-p ".git")
+ (let* ((remote-url (shell-command-to-string "git remote get-url origin 2>/dev/null"))
+ (repo-name (when (string-match "/\\([^/]+\\)\\.git" remote-url)
+ (match-string 1 remote-url))))
+ (cond
+ ((string= repo-name "home") (push "homelab" tags))
+ ((string-match-p "tekton" repo-name) (push "tekton" tags))
+ ((string-match-p "pipeline" repo-name) (push "tekton" tags)))))
+
+ ;; Detect from keywords in summary
+ (let ((summary-lower (downcase summary)))
+ ;; Development activities
+ (when (string-match-p "\\(bug\\|fix\\|debug\\)" summary-lower)
+ (push "debugging" tags))
+ (when (string-match-p "\\(feature\\|implement\\)" summary-lower)
+ (push "development" tags))
+ (when (string-match-p "refactor" summary-lower)
+ (push "refactoring" tags))
+ (when (string-match-p "\\(test\\|testing\\)" summary-lower)
+ (push "testing" tags))
+ (when (string-match-p "\\(doc\\|documentation\\)" summary-lower)
+ (push "documentation" tags))
+
+ ;; Infrastructure & tools
+ (when (string-match-p "\\(kubernetes\\|k8s\\)" summary-lower)
+ (push "kubernetes" tags))
+ (when (string-match-p "docker" summary-lower)
+ (push "docker" tags))
+ (when (string-match-p "\\(commit\\|push\\|git\\)" summary-lower)
+ (push "git" tags))
+ (when (string-match-p "\\(capture\\|journal\\)" summary-lower)
+ (push "journelly" tags))
+
+ ;; AI/LLM
+ (when (string-match-p "\\(llm\\|language model\\)" summary-lower)
+ (push "llm" tags))
+ (when (string-match-p "\\(ai\\|artificial intelligence\\)" summary-lower)
+ (push "ai" tags))
+ (when (string-match-p "claude" summary-lower)
+ (push "claude" tags))
+ (when (string-match-p "anthropic" summary-lower)
+ (push "anthropic" tags))
+ (when (string-match-p "gemini" summary-lower)
+ (push "gemini" tags))
+ (when (string-match-p "ollama" summary-lower)
+ (push "ollama" tags))
+ (when (string-match-p "\\(openai\\|chatgpt\\|gpt\\)" summary-lower)
+ (push "openai" tags))
+
+ ;; Cloud providers
+ (when (string-match-p "\\(cloud\\|infrastructure\\)" summary-lower)
+ (push "cloud" tags))
+ (when (string-match-p "\\(digitalocean\\|\\bdo\\b\\)" summary-lower)
+ (push "digitalocean" tags))
+ (when (string-match-p "\\(gcp\\|google cloud\\)" summary-lower)
+ (push "gcp" tags))
+ (when (string-match-p "oracle.*cloud" summary-lower)
+ (push "oracle-cloud" tags))
+ (when (string-match-p "\\(aws\\|amazon web services\\)" summary-lower)
+ (push "aws" tags))
+ (when (string-match-p "azure" summary-lower)
+ (push "azure" tags))
+
+ ;; Architecture
+ (when (string-match-p "\\(arm\\|aarch64\\)" summary-lower)
+ (push "arm" tags))
+ (when (string-match-p "x86.64" summary-lower)
+ (push "x86_64" tags))
+ (when (string-match-p "\\(cross.compile\\|cross compile\\)" summary-lower)
+ (push "cross-compile" tags))
+ (when (string-match-p "riscv" summary-lower)
+ (push "riscv" tags))
+
+ ;; Monitoring/Observability
+ (when (string-match-p "\\(monitoring\\|observability\\)" summary-lower)
+ (push "monitoring" tags))
+ (when (string-match-p "prometheus" summary-lower)
+ (push "prometheus" tags))
+ (when (string-match-p "grafana" summary-lower)
+ (push "grafana" tags))
+ (when (string-match-p "\\(alert\\|alerting\\)" summary-lower)
+ (push "alerting" tags))
+
+ ;; Media
+ (when (string-match-p "media" summary-lower)
+ (push "media" tags))
+ (when (string-match-p "jellyfin" summary-lower)
+ (push "jellyfin" tags))
+ (when (string-match-p "plex" summary-lower)
+ (push "plex" tags))
+
+ ;; Desktop/Window managers
+ (when (string-match-p "niri" summary-lower)
+ (push "niri" tags))
+ (when (string-match-p "sway" summary-lower)
+ (push "sway" tags))
+ (when (string-match-p "wayland" summary-lower)
+ (push "wayland" tags))
+ (when (string-match-p "x11" summary-lower)
+ (push "x11" tags))
+
+ ;; Networking
+ (when (string-match-p "\\(network\\|networking\\)" summary-lower)
+ (push "networking" tags))
+ (when (string-match-p "wireguard" summary-lower)
+ (push "wireguard" tags))
+ (when (string-match-p "\\(vpn\\|virtual private network\\)" summary-lower)
+ (push "vpn" tags))
+ (when (string-match-p "\\(dns\\|domain name\\)" summary-lower)
+ (push "dns" tags))
+
+ ;; Security
+ (when (string-match-p "security" summary-lower)
+ (push "security" tags))
+ (when (string-match-p "\\(auth\\|authentication\\)" summary-lower)
+ (push "auth" tags))
+ (when (string-match-p "\\(encryption\\|encrypt\\)" summary-lower)
+ (push "encryption" tags))
+ (when (string-match-p "\\(secret\\|agenix\\)" summary-lower)
+ (push "secrets" tags))
+ (when (string-match-p "yubikey" summary-lower)
+ (push "yubikey" tags))
+
+ ;; Backup/Storage
+ (when (string-match-p "backup" summary-lower)
+ (push "backup" tags))
+ (when (string-match-p "storage" summary-lower)
+ (push "storage" tags))
+ (when (string-match-p "syncthing" summary-lower)
+ (push "syncthing" tags))
+ (when (string-match-p "restic" summary-lower)
+ (push "restic" tags))
+
+ ;; Communication
+ (when (string-match-p "\\(email\\|mail\\)" summary-lower)
+ (push "email" tags))
+ (when (string-match-p "\\(mu4e\\|notmuch\\)" summary-lower)
+ (push "email" tags))
+ (when (string-match-p "xmpp" summary-lower)
+ (push "xmpp" tags))
+
+ ;; Databases
+ (when (string-match-p "\\(database\\|\\bdb\\b\\)" summary-lower)
+ (push "database" tags))
+ (when (string-match-p "\\(postgres\\|postgresql\\)" summary-lower)
+ (push "postgres" tags))
+ (when (string-match-p "sqlite" summary-lower)
+ (push "sqlite" tags))
+
+ ;; Web/HTTP
+ (when (string-match-p "\\(web\\|http\\|https\\)" summary-lower)
+ (push "web" tags))
+ (when (string-match-p "nginx" summary-lower)
+ (push "nginx" tags))
+ (when (string-match-p "caddy" summary-lower)
+ (push "caddy" tags))
+
+ ;; Hardware
+ (when (string-match-p "hardware" summary-lower)
+ (push "hardware" tags))
+ (when (string-match-p "\\(raspberry.pi\\|rpi\\)" summary-lower)
+ (push "raspberry-pi" tags))
+ (when (string-match-p "keyboard" summary-lower)
+ (push "keyboard" tags))
+
+ ;; Configuration
+ (when (string-match-p "home.manager" summary-lower)
+ (push "home-manager" tags))
+ (when (string-match-p "flake" summary-lower)
+ (push "flakes" tags))
+ (when (string-match-p "\\(deploy\\|deployment\\)" summary-lower)
+ (push "deployment" tags))
+ (when (string-match-p "\\(ci\\|cd\\|pipeline\\)" summary-lower)
+ (push "ci-cd" tags)))
+
+ ;; Remove duplicates and return
+ (delete-dups tags)))
+
(defun journelly-claude-session (summary)
"Add Claude session SUMMARY to today's Claude session entry.
+Auto-detects and appends tags based on context and content.
Creates entry if it doesn't exist, or appends to existing entry."
(interactive "sClaude session: ")
- (let ((timestamp (format-time-string "%H:%M")))
+ (let* ((timestamp (format-time-string "%H:%M"))
+ (tags (journelly--detect-tags summary))
+ (tags-string (if tags
+ (concat " " (mapconcat (lambda (tag) (concat "#" tag)) tags " "))
+ ""))
+ (entry (format "- %s :: %s%s\n" timestamp summary tags-string)))
(with-current-buffer (find-file-noselect org-journelly-file)
(save-excursion
(journelly-claude-capture-target)
- (insert (format "- %s :: %s\n" timestamp summary)))
+ (insert entry))
(save-buffer))
- (message "Claude session logged")))
+ (message "Claude session logged%s" (if tags (format " with tags: %s" tags-string) ""))))
(defun journelly-open ()
"Open Journelly.org file and jump to today's entry or top."