Agent skill

Annotate Project

by captainflasmr in captainflasmr/ollama-buddy

Analyse a project's source code and generate a simply-annotate database file with LLM-created annotations categorised by tag: defun for functions and large syntactical blocks, line for smaller…

GPL-3.0Auto-check passed

Install Annotate Project

skills CLI
$ npx skills add captainflasmr/ollama-buddy --skill annotate-project -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install captainflasmr/ollama-buddy annotate-project --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/captainflasmr/ollama-buddy.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/annotate-project .claude/skills/annotate-project && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
annotate-project
GitHub stars
103
Token cost
~6.2k tokens
SKILL.md length
1,553 words
Files
1
Skills in repo
12
Repo updated
First seen
Licence
GPL-3.0

At a glance

Analyse a project's source code and generate a simply-annotate database file with LLM-created annotations categorised by tag: defun for functions and large syntactical blocks, line for smaller…

  • Works in 10 steps: Discover Source Files → Determine the Database Path → Write the Elisp Helper Script → …
  • The user asks to annotate a project
  • SKILL.md covers Step 1: Discover Source Files, Step 2: Determine the Database…, Step 3: Write the Elisp Helper… and Step 4: Read and Analyse Each…, plus 7 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md

What it does

Annotate Project is an agent skill from captainflasmr/ollama-buddy. Analyse a project's source code and generate a simply-annotate database file with LLM-created annotations categorised by tag: defun for functions and large syntactical blocks, line for smaller sub-blocks. File-wide narrative lives in a sibling .org overview file, not in an overlay. Use this skill when the user asks to annotate a project, generate code descriptions, or create a simply-annotate database for a codebase. Trigger on phrases like "annotate this project", "generate annotations", "describe this…

Its SKILL.md is about 6.2k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

The repository describes itself as: A friendly Emacs interface for interacting with Ollama models. The licence is GPL-3.0.

When your agent uses it

  • The user asks to annotate a project
  • Generate code descriptions
  • Create a simply-annotate database for a codebase
  • Phrases like annotate this project

Example prompts

  • “annotate this project”
  • “generate annotations”
  • “describe this codebase”
  • “/annotate-project”

Workflow steps

10 steps, taken from the step headings in SKILL.md.

  1. Discover Source Files
  2. Determine the Database Path
  3. Write the Elisp Helper Script
  4. Read and Analyse Each File
  5. Produce Annotation JSON
  6. Backup the Existing Database
  7. Generate the Database
  8. Validate the Database
  9. Generate Directory Overview Org File
  10. Report

What it can do on your machine

Read from SKILL.md and the folder at commit 12eaf7f. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are bash, elisp, json and org).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Annotate Project loads about 6.2k tokens when it runs. Until then it costs about 149 tokens; SKILL.md has 1,553 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~149
When it runs · the whole SKILL.md, loaded when a task matches
~6.2k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from captainflasmr/ollama-buddy at commit 12eaf7f, republished under its GPL-3.0 licence (© captainflasmr). 1,553 words, ~6,213 tokens.

Download SKILL.mdSave it as .claude/skills/annotate-project/SKILL.md (or your agent's skills folder).
name
annotate-project
description
Analyse a project's source code and generate a simply-annotate database file with LLM-created annotations categorised by tag: `defun` for functions and large syntactical blocks, `line` for smaller sub-blocks. File-wide narrative lives in a sibling `.org` overview file, not in an overlay. Use this skill when the user asks to annotate a project, generate code descriptions, or create a simply-annotate database for a codebase. Trigger on phrases like "annotate this project", "generate annotations", "describe this codebase", "create annotations for", or "annotate the source".

Annotate Project Skill

You are generating a simply-annotate database file that describes a project's source code using two tag categories — defun (functions, classes, types, and other major syntactical blocks) and line (smaller sub-blocks worth calling out). When the user opens files in Emacs with simply-annotate-mode, they see these as tagged annotations they can filter and step through.

Important: simply-annotate's annotation model is tag-based, not level-based. The legacy level field (file/defun/line) no longer exists as a first-class concept — what used to be a level is now a tag on a thread-format annotation. File-wide overview annotations (overlays spanning the whole buffer) are not produced; that narrative lives exclusively in the sibling directory overview .org file created in Step 9.


Step 1: Discover Source Files

If the user provides a specific directory or glob argument (e.g. /annotate-project src/ or /annotate-project java/cuis-server), scan only that scope. Otherwise scan the project root.

Use the Glob tool to find files matching common source extensions:

  • **/*.el **/*.py **/*.js **/*.ts **/*.tsx **/*.jsx
  • **/*.rs **/*.go **/*.java **/*.c **/*.cpp **/*.h
  • **/*.rb **/*.lua **/*.sh **/*.clj **/*.hs **/*.proto
Directories to skip

Respect .gitignore and always skip these directories/patterns:

  • node_modules, vendor, dist, build, target, .git, __pycache__, .elc, .class
  • Directories named generated, gensrc, gen, auto-generated
  • Third-party / vendored code: third_party, thirdparty, extern, deps
File count guard

After discovering files, count them and report the total to the user before doing any reading or annotation. Include:

  1. The total number of source files found.
  2. A breakdown by immediate subdirectory (top 10 by count).
  3. Any directories that look auto-generated (containing generated, gensrc, gen, proto/generated, pb.go, .pb.h, etc.) — flag these and ask whether to include them.

If the file count exceeds 100 files, warn the user:

Found N source files. Annotating all of them will take a while. Would you like to proceed, or narrow the scope to a specific subdirectory?

Wait for confirmation before continuing. If the user narrows scope, re-discover within that scope.

If the count is ≤ 100, proceed automatically.


Step 2: Determine the Database Path

Annotations are stored in a project-local database file by default. This keeps each project's annotations self-contained, makes them shareable via version control if desired, and avoids one giant global database growing unbounded.

Resolve the database path in this order:

  1. Project-local (default). Find the project root by walking up from the current working directory looking for one of: .git, .hg, .svn, package.json, Cargo.toml, pyproject.toml, go.mod, pom.xml, build.gradle, build.gradle.kts, Makefile. Use that directory. If nothing is found, use the current working directory itself.

    Database path: <project-root>/.simply-annotations.el

  2. Global fallback. Only use ~/.emacs.d/simply-annotations.el if the user explicitly asks for the global database (e.g. "use the global db", "save to ~/.emacs.d/...").

Use the resolved path consistently in all subsequent steps (backup, generate, validate). Refer to it below as $DB_PATH.


Step 3: Write the Elisp Helper Script

Since the annotations target Emacs, use a native elisp batch script to convert line numbers to Emacs point positions. This guarantees byte offsets match what Emacs sees — no manual conversion needed.

The script produces annotations in the current thread-alist format used by simply-annotate:

elisp
((start . N)
 (end . N)
 (text . ((id . "thread-...")
          (created . "...")
          (status . "open")
          (priority . "normal")
          (tags . ("defun"))
          (comments . (((id . "comment-...")
                        (parent-id . nil)
                        (author . "Claude")
                        (timestamp . "...")
                        (text . "The actual annotation text")
                        (type . "comment")))))))

It also accepts an optional project root third argument. When supplied, the DB keys are rewritten to project-relative paths (src/foo.ts rather than /home/user/project/src/foo.ts) — this is required for project-local databases, because simply-annotate's simply-annotate--file-key returns a project-relative path when looking up annotations, and a DB keyed by absolute paths will silently find nothing.

Write the following script verbatim to /tmp/gen_annotations.el at the start of the session. Do not modify it — it is tested and known to work.

elisp
;;; gen_annotations.el --- Convert line-based annotation JSON to simply-annotate (thread-tag format) -*- lexical-binding: t; -*-

;; Usage: emacs --batch -l /tmp/gen_annotations.el /tmp/annotations.json $DB_PATH [PROJECT_ROOT]
;;
;; When PROJECT_ROOT is supplied, keys are rewritten to project-relative paths.
;; This is REQUIRED for project-local databases.
;;
;; Input JSON shape (per file):
;;   { "/abs/path/file.ts": [
;;       {"sl": 8, "el": 52, "text": "...", "tag": "defun"},
;;       {"sl": 32, "el": 51, "text": "...", "tag": "line"}
;;     ] }

(require 'json)
(require 'cl-lib)

(defvar gen-annotations--counter 0)

(defun gen-annotations--uid (prefix)
  "Return a stable unique id with PREFIX."
  (setq gen-annotations--counter (1+ gen-annotations--counter))
  (format "%s-%s-%06d"
          prefix
          (format-time-string "%s")
          gen-annotations--counter))

(defun gen-annotations--make-thread (text tag)
  "Wrap TEXT into a minimal thread alist tagged with TAG."
  (let ((now (format-time-string "%Y-%m-%dT%H:%M:%S%z")))
    `((id . ,(gen-annotations--uid "thread"))
      (created . ,now)
      (status . "open")
      (priority . "normal")
      (tags . (,tag))
      (comments . (((id . ,(gen-annotations--uid "comment"))
                    (parent-id . nil)
                    (author . "Claude")
                    (timestamp . ,now)
                    (text . ,text)
                    (type . "comment")))))))

(defun gen-annotations--line-to-point (buf line-number)
  "In BUF, return the point at the beginning of LINE-NUMBER (1-based)."
  (with-current-buffer buf
    (save-excursion
      (goto-char (point-min))
      (if (and (> line-number 0)
               (zerop (forward-line (1- line-number))))
          (point)
        (point-max)))))

(defun gen-annotations--end-of-line-region (buf line-number)
  "In BUF, return the point at end of LINE-NUMBER (1-based)."
  (with-current-buffer buf
    (save-excursion
      (goto-char (point-min))
      (if (and (> line-number 0)
               (zerop (forward-line (1- line-number))))
          (line-end-position)
        (point-max)))))

(defun gen-annotations--convert-file (filepath annotations)
  "Convert ANNOTATIONS for FILEPATH from line numbers to point positions.
Each input annotation has keys sl, el, text, tag."
  (if (not (file-exists-p filepath))
      (progn
        (message "WARNING: File not found, skipping: %s" filepath)
        nil)
    (let ((buf (generate-new-buffer " *gen-ann-temp*"))
          result)
      (unwind-protect
          (progn
            (with-current-buffer buf
              (insert-file-contents filepath))
            (dolist (ann annotations)
              (let* ((sl (alist-get 'sl ann))
                     (el (alist-get 'el ann))
                     (text (alist-get 'text ann))
                     (tag (alist-get 'tag ann))
                     (start (gen-annotations--line-to-point buf sl))
                     (end (if (= el -1)
                              (with-current-buffer buf (point-max))
                            (gen-annotations--end-of-line-region buf el)))
                     (thread (gen-annotations--make-thread text tag)))
                (push `((start . ,start)
                        (end . ,end)
                        (text . ,thread))
                      result))))
        (kill-buffer buf))
      ;; Sort by start position, ascending.
      (sort (nreverse result)
            (lambda (a b) (< (alist-get 'start a) (alist-get 'start b)))))))

(defun gen-annotations--load-existing (output-path)
  "Load existing database from OUTPUT-PATH if it exists."
  (when (file-exists-p output-path)
    (with-temp-buffer
      (insert-file-contents output-path)
      (let ((content (string-trim (buffer-string))))
        (unless (string-empty-p content)
          (condition-case err
              (car (read-from-string content))
            (error
             (message "WARNING: Could not parse existing database: %s"
                      (error-message-string err))
             nil)))))))

(defun gen-annotations--db-key (filepath project-root)
  "Return the DB key for FILEPATH, made project-relative when PROJECT-ROOT is set."
  (if (and project-root
           (stringp project-root)
           (> (length project-root) 0)
           (string-prefix-p (file-name-as-directory project-root) filepath))
      (substring filepath (length (file-name-as-directory project-root)))
    filepath))

(defun gen-annotations--main ()
  "Main entry point for batch annotation generation."
  (let* ((args (last command-line-args 3))
         (json-path (nth 0 args))
         (output-path (and (nth 1 args) (expand-file-name (nth 1 args))))
         (project-root (and (nth 2 args)
                            (file-name-as-directory
                             (expand-file-name (nth 2 args))))))

    (unless (and json-path output-path)
      (error "Usage: emacs --batch -l gen_annotations.el /tmp/annotations.json output.el [project-root]"))

    (let* ((json-object-type 'alist)
           (json-array-type 'list)
           (json-key-type 'symbol)
           (annotations (with-temp-buffer
                          (insert-file-contents json-path)
                          (json-read)))
           (existing-db (gen-annotations--load-existing output-path))
           (new-db existing-db)
           (file-count 0))

      (dolist (entry annotations)
        (let* ((filepath (symbol-name (car entry)))
               (db-key (gen-annotations--db-key filepath project-root))
               (file-annotations (cdr entry))
               ;; Read from absolute filepath for line-to-point conversion;
               ;; only the DB key is made relative.
               (converted (gen-annotations--convert-file filepath file-annotations)))
          (when converted
            (cl-incf file-count)
            (if (assoc db-key new-db #'string=)
                (setcdr (assoc db-key new-db #'string=) converted)
              (push (cons db-key converted) new-db)))))

      (setq new-db (sort new-db (lambda (a b) (string< (car a) (car b)))))

      (with-temp-file output-path
        (insert ";;; Simply Annotate Database\n")
        (insert ";;; This file is auto-generated. Do not edit manually.\n\n")
        (let ((print-level nil)
              (print-length nil))
          (prin1 new-db (current-buffer)))
        (insert "\n"))

      (message "Generated annotations for %d files -> %s" file-count output-path))))

(gen-annotations--main)

Step 4: Read and Analyse Each File

For each source file, read the contents and produce annotations under two tags: defun and line. Record annotations using line numbers (sl/el) — the helper script will convert to byte offsets.

Do not produce file-wide overlay annotations. In the previous model there was a file level covering the whole buffer (sl: 1, el: -1). That overlay is no longer part of the new format — a single annotation spanning the whole file overlaps every other annotation and confuses tag filtering. The file's high-level narrative belongs in the sibling .org overview file created in Step 9, where it can be read as prose.

Tag: defun

One annotation per major syntactical block:

  • Elisp: defun, defmacro, defvar, defcustom, defclass, define-minor-mode, use-package blocks
  • Python: def, class, top-level decorators
  • JavaScript/TypeScript: function, class, arrow function assignments, export default, React components
  • Rust: fn, impl, struct, enum, trait, mod
  • Go: func, type, interface
  • C/C++: function definitions, struct/class/enum definitions
  • Ruby: def, class, module
  • Java: method definitions, class definitions
  • Shell: function definitions
  • Proto: message, enum, service, rpc definitions

The annotation sl and el should span the full block (from the first line of the definition to the closing delimiter line). Write a description covering: what it does, parameters/return values (briefly), key side effects, and how it relates to the rest of the file. 1-3 sentences.

Skip defun-tagged annotations for trivial files (< 30 lines, or pure boilerplate like single-exception classes, simple data holders, or marker interfaces).

Tag: line

Annotations for smaller but meaningful sub-blocks within defun-tagged regions:

  • Significant let/let* binding blocks
  • Important conditional branches (if/cond/pcase/match/switch)
  • Loop bodies with non-trivial logic
  • Error handling blocks (condition-case, try/catch/except)
  • Key variable assignments that control flow
  • Non-obvious expressions that benefit from explanation

Do NOT annotate every line — focus on blocks where a reader would benefit from context. Aim for roughly 3-8 line-tagged annotations per defun-tagged block, fewer for simple functions. Skip line annotations entirely for simple functions.


Step 5: Produce Annotation JSON

Collect all annotations into a single JSON object. Use absolute paths as the keys (the helper script will rewrite them to project-relative paths using the project-root argument in Step 7):

json
{
  "/absolute/path/to/file.java": [
    {"sl": 25, "el": 80, "text": "Class description...", "tag": "defun"},
    {"sl": 42, "el": 55, "text": "Key conditional...", "tag": "line"}
  ]
}

Note there is no file-wide entry (sl: 1, el: -1) — that narrative goes into the .org overview file in Step 9.

Write this JSON to /tmp/annotations.json.


Show full SKILL.md (593 more words)Show less

Step 6: Backup the Existing Database

Before generating, always back up the current database if it exists. Use the $DB_PATH resolved in Step 2:

bash
cp "$DB_PATH" "$DB_PATH.bak" 2>/dev/null || true

This ensures the user can recover if the generation or merge corrupts the file. If something goes wrong, restore with: cp "$DB_PATH.bak" "$DB_PATH".


Step 7: Generate the Database

Run the elisp helper script (written in Step 3) against $DB_PATH. Pass the project root as a third argument so keys are written as project-relative paths — without this, simply-annotate will fail to find the annotations when the user opens a file:

bash
emacs --batch -l /tmp/gen_annotations.el /tmp/annotations.json "$DB_PATH" "$PROJECT_ROOT"

Where $PROJECT_ROOT is the directory resolved in Step 2 (the one containing .simply-annotations.el). Omit the project-root argument only when using the global database under ~/.emacs.d/, which keys by absolute path.

The script handles everything:

  • Merging: files already in the database are replaced; files not in the new JSON are preserved untouched.
  • Key rewriting: when PROJECT_ROOT is supplied, absolute paths inside that root become project-relative (e.g. src/index.ts).
  • Thread format: each annotation's text is a full thread alist with tags, matching the current simply-annotate on-disk format.
  • Format: output is written with prin1, matching simply-annotate--save-database format — a raw alist readable by read-from-string. No (setq ...) wrapper.

Step 8: Validate the Database

After generating, always run the validation script to confirm the database is well-formed and won't break simply-annotate-mode. Write the following verbatim to /tmp/validate_annotations.el and run it against $DB_PATH.

elisp
;;; validate_annotations.el --- Validate a simply-annotate thread-tag database -*- lexical-binding: t; -*-

;; Usage: emacs --batch -l /tmp/validate_annotations.el $DB_PATH

(require 'cl-lib)

(defun validate-annotations--thread-p (obj)
  "Return non-nil if OBJ looks like a simply-annotate thread alist."
  (and (listp obj)
       (listp (car-safe obj))
       (assq 'id obj)
       (assq 'comments obj)))

(defun validate-annotations--main ()
  "Validate the simply-annotate database file."
  (let* ((db-path (expand-file-name (car (last command-line-args))))
         (errors 0)
         (warnings 0)
         (total-annotations 0)
         (tag-counts (make-hash-table :test 'equal))
         db)

    (unless (file-exists-p db-path)
      (message "FAIL: Database file does not exist: %s" db-path)
      (kill-emacs 1))

    ;; Step 1: Can we read it?
    (condition-case err
        (with-temp-buffer
          (insert-file-contents db-path)
          (setq db (car (read-from-string (string-trim (buffer-string))))))
      (error
       (message "FAIL: Cannot parse database: %s" (error-message-string err))
       (kill-emacs 1)))

    ;; Step 2: Is it a list?
    (unless (listp db)
      (message "FAIL: Database is not a list (got %s)" (type-of db))
      (kill-emacs 1))

    ;; Step 3: Validate each entry
    (dolist (entry db)
      (let ((filepath (car entry))
            (annotations (cdr entry)))

        (unless (stringp filepath)
          (message "ERROR: Entry key is not a string: %S" filepath)
          (cl-incf errors))

        (unless (listp annotations)
          (message "ERROR: Annotations for %s is not a list" filepath)
          (cl-incf errors))

        ;; File-existence check: project-relative keys won't exist as absolute
        ;; paths, so skip the check for non-absolute keys.
        (when (and (stringp filepath)
                   (file-name-absolute-p filepath)
                   (not (file-exists-p filepath)))
          (message "WARNING: File does not exist: %s" filepath)
          (cl-incf warnings))

        (dolist (ann annotations)
          (cl-incf total-annotations)
          (let ((start (alist-get 'start ann))
                (end   (alist-get 'end ann))
                (text  (alist-get 'text ann)))

            (unless (and start end text)
              (message "ERROR: %s: annotation missing required fields: %S" filepath ann)
              (cl-incf errors))

            (when (and start (not (and (integerp start) (> start 0))))
              (message "ERROR: %s: invalid start: %S" filepath start)
              (cl-incf errors))
            (when (and end (not (and (integerp end) (> end 0))))
              (message "ERROR: %s: invalid end: %S" filepath end)
              (cl-incf errors))
            (when (and start end (integerp start) (integerp end) (> start end))
              (message "ERROR: %s: start (%d) > end (%d)" filepath start end)
              (cl-incf errors))

            ;; text must be a string OR a thread alist.
            (unless (or (stringp text)
                        (validate-annotations--thread-p text))
              (message "ERROR: %s: text is neither a string nor a thread alist: %S"
                       filepath text)
              (cl-incf errors))

            ;; Accumulate tag counts for reporting.
            (when (validate-annotations--thread-p text)
              (dolist (tag (alist-get 'tags text))
                (puthash tag (1+ (gethash tag tag-counts 0)) tag-counts)))))))

    ;; Report
    (message "Validation complete: %d files, %d annotations, %d errors, %d warnings"
             (length db) total-annotations errors warnings)
    (when (> (hash-table-count tag-counts) 0)
      (message "Tag breakdown:")
      (maphash (lambda (tag count) (message "  %s: %d" tag count)) tag-counts))

    (if (> errors 0)
        (progn
          (message "FAIL: Database has %d errors. Restore backup with:" errors)
          (message "  cp %s.bak %s" db-path db-path)
          (kill-emacs 1))
      (message "OK: Database is valid.")
      (kill-emacs 0))))

(validate-annotations--main)

Run with:

bash
emacs --batch -l /tmp/validate_annotations.el "$DB_PATH"

If validation fails, immediately restore the backup:

bash
cp "$DB_PATH.bak" "$DB_PATH"

Then investigate the /tmp/annotations.json for the bad data and re-run generation.


Step 9: Generate Directory Overview Org File

For the annotated directory, create an org file alongside it with the same name as the directory. For example, annotating /project/java/client creates /project/java/client.org.

The org file should contain:

org
#+TITLE: <directory-name> — Directory Overview
#+AUTO_TANGLE: nil

* Purpose

<2-4 sentence overview of what this directory/module does and its role in the
wider project.>

* Structure

<Brief description of how the directory is organised — subdirectories, key
groupings of files, and the relationships between them.>

** <subdirectory-or-grouping-1>

<1-2 sentences on what this group of files does.>

** <subdirectory-or-grouping-2>

...

* Key Files

| File | Description |
|------+-------------|
| file1.java | One-line summary |
| file2.java | One-line summary |
| ... | ... |

List ALL source files in the directory scope, not just the "important" ones.
Group by subdirectory if the directory has subdirectories.

* Important Notes

<Bullet points covering anything a newcomer should know: key patterns used,
auto-generated files to ignore, non-obvious conventions, gotchas, entry points,
important interfaces, etc. Skip this section if there is nothing noteworthy.>
Rules for the org file
  • One org file per annotated directory scope — if the user annotates java/client, create java/client.org. If they annotate java/cuis-server, create java/cuis-server.org.
  • The file sits alongside (as a sibling of) the directory, not inside it.
  • Keep it concise — this is a quick-reference map, not exhaustive documentation.
  • The Key Files table and Structure section are the primary home for file-wide narrative (since there is no file-level overlay annotation). Each file's one-line summary here is what a file-level annotation used to provide.
  • If the directory has auto-generated subdirectories (e.g. gensrc/), note them in Important Notes.

Step 10: Report

After writing, report:

  • Number of files annotated
  • Total annotations generated (broken down by tag — defun and line)
  • The database file path (clearly state whether it is project-local or global)
  • Validation result (pass/fail)
  • The directory overview org file path
  • Remind the user to open files in Emacs and enable simply-annotate-mode (or use simply-annotate-show-all for the global overview)

Guidelines

  • Be concise: defun-tagged descriptions 1-3 sentences; line-tagged 1 sentence. File-wide overview prose lives in the .org overview file (2-4 sentences per file in the Key Files table).
  • Be descriptive, not prescriptive: Describe what the code does, not what it should do. This is documentation, not code review.
  • Use plain language: Avoid jargon where possible. The goal is to help someone unfamiliar with the codebase orient themselves.
  • Process files in parallel: Use the Agent tool to analyse multiple files simultaneously when practical — but keep batches reasonable (10-20 files per agent).
  • Handle large files: For files over 1000 lines, you may need to read them in chunks. Still produce annotations for the full file.
  • Respect the user's scope: If they say "just the src/ directory" or "only Python files", honour that constraint.
  • Don't annotate the world: The goal is useful coverage of code the user cares about, not exhaustive annotation of every file in the repo.

© captainflasmr, GPL-3.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .agents/skills/annotate-project of captainflasmr/ollama-buddy.

Open the folder on GitHubat commit 12eaf7f

Compare with similar skills

Annotate Project next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Annotate Project compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Annotate Project this skillcaptainflasmr/ollama-buddy103—~6.2kAutomated safety check: PassGPL-3.0
Wireframe Annotatednexu-io/open-design100k—~960Automated safety check: PassApache-2.0
Arize Annotationgithub/awesome-copilot40k1 repos~2.7kAutomated safety check: NotesMIT
Image Annotationsgithub/awesome-copilot40k—~6kAutomated safety check: PassMIT
Plannotator Annotatebacknotprop/plannotator9.2k—~163Automated safety check: PassApache-2.0
Bio Genome Annotation Annotation QcGPTomics/bioSkills1.2k1 repos~3.6kAutomated safety check: PassMIT

Similar skills

  • Wireframe Annotated

    nexu-io/open-design

    An annotated / redline lo-fi wireframe — a desktop landing/marketing page drawn as flat greyboxes inside a browser chrome frame, overlaid with numbered annotation pins (①②③④⑤) in a single accent…

    100k GitHub stars~960 tokensUpdated today
    Frontend & DesignAuto-check passed
  • Arize Annotation

    github/awesome-copilot

    Official

    Creates and manages annotation configs (categorical, continuous, freeform label schemas) and annotation queues (human review workflows) on Arize.

    40k GitHub starsUsed in 1 repo~2.7k tokens
    Auto-check: notes
  • Image Annotations

    github/awesome-copilot

    Official

    Annotate screenshots, diagrams, and images with callout rectangles, arrows, labels, and color-coded highlights using PIL.

    40k GitHub stars~6k tokensUpdated today
    DevelopmentAuto-check passed
  • Plannotator Annotate

    backnotprop/plannotator

    Open Plannotator's annotation UI for a file, folder, or URL, then address the returned annotations.

    9.2k GitHub stars~163 tokensUpdated today
    Auto-check passed
  • Assesses the quality and completeness of a genome annotation with BUSCO (conserved single-copy ortholog recovery), OMArk (proteome completeness, consistency, and contamination), CheckM2 (prokaryotic…

    1.2k GitHub starsUsed in 1 repo~3.6k tokens
    Research & ScienceAuto-check passed
  • Transfers gene annotations between genome assemblies via coordinate liftover (UCSC liftOver, CrossMap for same-species version updates) or feature/sequence projection (Liftoff for same/close…

    1.2k GitHub starsUsed in 1 repo~4k tokens
    Research & ScienceAuto-check passed

More from captainflasmr/ollama-buddy

All 12 skills in this repo
  • Blog Writer

    captainflasmr/ollama-buddy

    Write an Emacs blog post in James Dyer's voice for www.emacs.dyerdwelling.family.

    103 GitHub stars~2.1k tokensUpdated 28 days ago
    Auto-check passed
  • Elisp Dev

    captainflasmr/ollama-buddy

    Assist with Emacs Lisp (elisp) development, debugging, and parenthesis matching.

    103 GitHub stars~2.7k tokensUpdated 28 days ago
    Auto-check passed
  • Elisp Review

    captainflasmr/ollama-buddy

    Review Emacs Lisp (elisp) packages for bugs, style/convention violations, and optimisation opportunities.

    103 GitHub stars~2.2k tokensUpdated 28 days ago
    Auto-check passed
  • Reddit Post Writer

    captainflasmr/ollama-buddy

    Write an r/emacs Reddit post in James Dyer's voice for announcing or discussing an Emacs package.

    103 GitHub stars~1.4k tokensUpdated 28 days ago
    Auto-check passed
  • Code Refactoring

    captainflasmr/ollama-buddy

    Expert code refactoring and optimization with analysis, improvements, and documentation.

    103 GitHub stars~446 tokensUpdated 28 days ago
    Auto-check passed
  • Emacs Blog Reviewer

    captainflasmr/ollama-buddy

    Review Emacs blog posts for technical accuracy, naming conventions, and correct Emacs idioms.

    103 GitHub stars~751 tokensUpdated 28 days ago
    Auto-check passed

Questions about Annotate Project

What does Annotate Project do?

Analyse a project's source code and generate a simply-annotate database file with LLM-created annotations categorised by tag: defun for functions and large syntactical blocks, line for smaller…. Annotate Project is an agent skill from captainflasmr/ollama-buddy. Analyse a project's source code and generate a simply-annotate database file with LLM-created annotations categorised by tag: defun for functions and large syntactical blocks, line for smaller sub-blocks.

When should I use Annotate Project?

Annotate Project fits situations like: the user asks to annotate a project; generate code descriptions; create a simply-annotate database for a codebase; phrases like annotate this project.

How do I install Annotate Project in Claude Code?

Run `npx skills add captainflasmr/ollama-buddy --skill annotate-project -a claude-code`. Or copy the skill folder (.agents/skills/annotate-project in captainflasmr/ollama-buddy) into .claude/skills/annotate-project in your project. Claude Code loads it when a task matches its description.

How do I install Annotate Project in Codex?

Run `npx skills add captainflasmr/ollama-buddy --skill annotate-project -a codex`. Or copy the skill folder (.agents/skills/annotate-project in captainflasmr/ollama-buddy) into .agents/skills/annotate-project in your project. Codex loads it when a task matches its description.

Can I use Annotate Project in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add captainflasmr/ollama-buddy --skill annotate-project -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/annotate-project, .gemini/skills/annotate-project, .github/skills/annotate-project and .opencode/skills/annotate-project in your project.

What does Annotate Project need to run?

SKILL.md names no scripts, command-line tools or credentials: Annotate Project is instructions for the agent only.

Does Annotate Project access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Annotate Project safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Annotate Project use?

Annotate Project is published under the GPL-3.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Annotate Project use?

About 6.2k tokens (SKILL.md is roughly 25k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Annotate Project?

Skills that share tags, products or a category with Annotate Project: Wireframe Annotated (nexu-io/open-design, 100k stars), Arize Annotation (github/awesome-copilot, 40k stars), Image Annotations (github/awesome-copilot, 40k stars) and Plannotator Annotate (backnotprop/plannotator, 9.2k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Annotate Project?

captainflasmr (a GitHub user) maintains it in captainflasmr/ollama-buddy, which has 103 GitHub stars. The repository holds 12 skills in this directory. The repository was last updated on September 10, 2026.

Source: captainflasmr/ollama-buddy on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.