diff --git a/bin/convert-prompts-folder-to-prompt-log b/bin/convert-prompts-folder-to-prompt-log
new file mode 100755
index 0000000..3597f6d
--- /dev/null
+++ b/bin/convert-prompts-folder-to-prompt-log
@@ -0,0 +1,101 @@
+#!/usr/bin/env bash
+
+convert-prompts-folder-to-prompt-log() {
+ local repo_path="${1:-.}"
+
+ if [[ ! -d "$repo_path/.git" ]]; then
+ echo "Error: No .git directory found in $repo_path."
+ return 1
+ fi
+
+ local prompts_dir="$repo_path/prompts"
+
+ if [[ ! -d "$prompts_dir" ]]; then
+ echo "No prompts directory found at $prompts_dir."
+ return 0
+ fi
+
+ local original_dir
+ original_dir="$(pwd)"
+ cd "$repo_path" || { echo "Cannot change to $repo_path"; return 1; }
+
+ if [[ ! -d "tmp/prompt-log" ]] || ! git worktree list | grep -qF "$(pwd)/tmp/prompt-log"; then
+ echo "Creating prompt-log worktree."
+ if ! git show-ref --verify --quiet refs/heads/prompt-log; then
+ local current_branch
+ current_branch="$(git rev-parse --abbrev-ref HEAD)"
+ if [[ "$current_branch" == "prompt-log" ]]; then
+ echo "Error: Cannot create prompt-log worktree while on prompt-log branch."
+ cd "$original_dir" || true
+ return 1
+ fi
+ local empty_tree="4b825dc642cb6eb9a060e54bf8d69288fbee4904"
+ local orphan_commit
+ orphan_commit="$(echo "init: prompt-log branch" | git commit-tree "$empty_tree")"
+ git branch prompt-log "$orphan_commit"
+ fi
+ mkdir -p tmp
+ git worktree add "tmp/prompt-log" prompt-log
+ fi
+
+ local worktree_path="tmp/prompt-log"
+ local -a skipped
+ local converted=0
+
+ for file in "$prompts_dir"/*.md; do
+ if [[ ! -f "$file" ]]; then
+ continue
+ fi
+
+ local filename
+ filename="$(basename "$file")"
+
+ local creation_commit
+ creation_commit="$(git log --follow --diff-filter=A --format="%h" -- "$file" | tail -n 1)"
+
+ if [[ -z "$creation_commit" ]]; then
+ skipped+=("$filename")
+ continue
+ fi
+
+ local title
+ title="$(grep -m1 '^title:' "$file" | sed 's/^title:[[:space:]]*//; s/^"\(.*\)"$/\1/; s/'"'"'\(.*\)'"'"'$/\1/')"
+
+ if [[ -z "$title" ]]; then
+ title="untitled"
+ fi
+
+ local slug
+ slug=$(echo "$title" | tr '[:upper:]' '[:lower:]' | tr '.' '-' | tr ' ' '-' | tr -cd '[:alnum:]-')
+
+ local target_filename="${creation_commit}-${slug}.md"
+ local target_path="$worktree_path/$target_filename"
+
+ cp "$file" "$target_path"
+
+ (
+ cd "$worktree_path" || exit 1
+ git add "$target_filename"
+ git commit -m "feat: add prompt file" -m "$target_filename"
+ ) || { echo "Error: Failed to commit $target_filename"; continue; }
+
+ converted=$((converted + 1))
+ done
+
+ if [[ ${#skipped[@]} -gt 0 ]]; then
+ echo "Skipped files with no discoverable creation commit:"
+ printf '%s\n' "${skipped[@]}"
+ fi
+
+ echo "Converted $converted prompt file(s)."
+
+ if [[ $converted -gt 0 ]]; then
+ rm -rf "$prompts_dir"
+ echo "Removed old $prompts_dir folder."
+ fi
+
+ cd "$original_dir" || true
+}
+cpfpl() {
+ convert-prompts-folder-to-prompt-log "$@"
+}
diff --git a/bin/create-prompt b/bin/create-prompt
index 55f540c..8d6d80d 100755
--- a/bin/create-prompt
+++ b/bin/create-prompt
@@ -5,57 +5,27 @@ create-prompt() {
if [[ -z "$title" ]]; then
echo "Error: Title cannot be empty."
- echo "Usage: task create-prompt
"
+ echo "Usage: task create-prompt [repo-path]"
return 1
fi
-
- local prompts_dir="prompts"
- if [ -n "$2" ]; then
- prompts_dir="$2/prompts"
- fi
- if [[ ! -d "$prompts_dir" ]]; then
- mkdir -p "$prompts_dir"
- fi
-
- local highest_num=0
- for file in "$prompts_dir"/[0-9][0-9]_*.md; do
- if [[ -f "$file" ]]; then
- local num=${file#"$prompts_dir"/}
- num=${num%%_*}
- num=${num//[!0-9]/}
- if [[ -n "$num" ]] && (( 10#$num > highest_num )); then
- highest_num=$((10#$num))
- fi
- fi
- done
+ local repo_path="${2:-.}"
+ local prompt_file="$repo_path/prompt.md"
+
+ local git_author
+ git_author="$(git log --format="%an <%ae>" -1 2>/dev/null || echo '')"
- local next_num=$((highest_num + 1))
- local padded_num=$(printf "%02d" "$next_num")
-
- local slug=$(echo "$title" | tr '[:upper:]' '[:lower:]'| tr '.' '-' | tr ' ' '-' | tr -cd '[:alnum:]-')
- local filename="${padded_num}_${slug}.md"
- local filepath="$prompts_dir/$filename"
-
- if [[ -f "$filepath" ]]; then
- echo "Error: File $filepath already exists."
- return 1
- fi
-
export PROMPT_TITLE="$title"
- export PROMPT_ID="$padded_num"
- envsubst < "$HOME/taskfile.build/prompt.md.template" > "$filepath"
-
+ export PROMPT_AUTHOR="${git_author:-}"
+
+ envsubst < "$HOME/taskfile.build/prompt.md.template" > "$prompt_file"
+
if [[ -n "$EDITOR" ]]; then
- "$EDITOR" "$filepath"
+ "$EDITOR" "$prompt_file"
fi
- echo 'File created:'
- echo "$filepath"
-
- # Copy path to clipboard
- echo "$filepath" | copy-to-clipboard
- echo "Path to prompt file copied to clipboard."
+ echo "File created:"
+ echo "$prompt_file"
}
crp() {
create-prompt "$@"
diff --git a/bin/edit-prompt b/bin/edit-prompt
new file mode 100755
index 0000000..364f8a6
--- /dev/null
+++ b/bin/edit-prompt
@@ -0,0 +1,93 @@
+#!/usr/bin/env bash
+
+edit-prompt() {
+ local commit=""
+ local repo_path="${2:-.}"
+
+ if [[ -n "$1" ]]; then
+ if [[ -n "$2" ]]; then
+ commit="$1"
+ elif [[ "$1" == */* ]] || [[ "$1" == "." ]]; then
+ repo_path="$1"
+ else
+ commit="$1"
+ fi
+ fi
+
+ if [[ ! -d "$repo_path/.git" ]]; then
+ echo "Error: No .git directory found in $repo_path."
+ return 1
+ fi
+
+ local worktree_path="$repo_path/tmp/prompt-log"
+
+ if [[ ! -d "$worktree_path" ]]; then
+ echo "No prompt-log worktree found. Run init-prompt-log first."
+ return 1
+ fi
+
+ local target_file
+
+ if [[ -z "$commit" ]]; then
+ if ! command -v fzf &> /dev/null; then
+ echo "Error: fzf is required for interactive selection."
+ return 1
+ fi
+
+ local selected
+ selected="$(
+ for f in "$worktree_path"/*.md; do
+ if [[ -f "$f" ]]; then
+ local f_title
+ f_title="$(grep -m1 '^title:' "$f" | sed 's/^title:[[:space:]]*//; s/^"\(.*\)"$/\1/; s/'"'"'\(.*\)'"'"'$/\1/')"
+ echo "$(basename "$f"): $f_title"
+ fi
+ done | fzf | cut -d: -f1
+ )"
+
+ if [[ -z "$selected" ]]; then
+ echo "No prompt selected."
+ return 0
+ fi
+
+ target_file="$worktree_path/$selected"
+ else
+ local matching_files=()
+ for f in "$worktree_path"/${commit}*.md; do
+ if [[ -f "$f" ]]; then
+ matching_files+=("$f")
+ fi
+ done
+
+ if [[ ${#matching_files[@]} -eq 0 ]]; then
+ echo "Error: No prompt file found starting with commit prefix '$commit'."
+ return 1
+ elif [[ ${#matching_files[@]} -gt 1 ]]; then
+ echo "Error: Ambiguous commit prefix '$commit'. Matches:"
+ printf '%s\n' "${matching_files[@]}"
+ return 1
+ fi
+
+ target_file="${matching_files[0]}"
+ fi
+
+ if [[ -n "$EDITOR" ]]; then
+ "$EDITOR" "$target_file"
+ else
+ echo "Set EDITOR to open the prompt file automatically."
+ return 1
+ fi
+
+ local filename
+ filename="$(basename "$target_file")"
+
+ (
+ cd "$worktree_path" || exit 1
+ git add "$filename"
+ git commit -m "feat: update prompt file" -m "$filename"
+ git push 2>/dev/null || echo "Warning: push failed."
+ ) || echo "Warning: commit/push step failed."
+}
+ep() {
+ edit-prompt "$@"
+}
diff --git a/bin/init-prompt-log b/bin/init-prompt-log
new file mode 100755
index 0000000..957d505
--- /dev/null
+++ b/bin/init-prompt-log
@@ -0,0 +1,54 @@
+#!/usr/bin/env bash
+
+init-prompt-log() {
+ local repo_path="${1:-.}"
+
+ if [[ ! -d "$repo_path/.git" ]]; then
+ echo "Error: No .git directory found in $repo_path."
+ return 1
+ fi
+
+ local original_dir
+ original_dir="$(pwd)"
+ cd "$repo_path" || { echo "Cannot change to $repo_path"; return 1; }
+
+ local current_branch
+ current_branch="$(git rev-parse --abbrev-ref HEAD)"
+
+ if [[ "$current_branch" == "prompt-log" ]]; then
+ if [[ -d "tmp/prompt-log" ]] && git worktree list | grep -qF "$(pwd)/tmp/prompt-log"; then
+ echo "prompt-log worktree already exists at tmp/prompt-log."
+ cd "$original_dir" || true
+ return 0
+ fi
+ echo "Error: Cannot create prompt-log worktree while on prompt-log branch. Switch to another branch first."
+ cd "$original_dir" || true
+ return 1
+ fi
+
+ if ! git show-ref --verify --quiet refs/heads/prompt-log; then
+ local empty_tree="4b825dc642cb6eb9a060e54bf8d69288fbee4904"
+ local orphan_commit
+ orphan_commit="$(echo "init: prompt-log branch" | git commit-tree "$empty_tree")"
+ git branch prompt-log "$orphan_commit"
+ fi
+
+ if git rev-parse --abbrev-ref origin/prompt-log &>/dev/null; then
+ echo "Remote branch origin/prompt-log already exists."
+ elif git remote &>/dev/null; then
+ git push -u origin prompt-log 2>/dev/null || echo "Warning: could not push prompt-log to remote."
+ fi
+
+ if [[ -d "tmp/prompt-log" ]] && git worktree list | grep -qF "$(pwd)/tmp/prompt-log"; then
+ echo "prompt-log worktree already exists at tmp/prompt-log."
+ else
+ mkdir -p tmp
+ git worktree add "tmp/prompt-log" prompt-log
+ echo "Created prompt-log worktree at tmp/prompt-log."
+ fi
+
+ cd "$original_dir" || true
+}
+ipl() {
+ init-prompt-log "$@"
+}
diff --git a/bin/list-prompts b/bin/list-prompts
index 75f11bc..bb2e77f 100755
--- a/bin/list-prompts
+++ b/bin/list-prompts
@@ -1,58 +1,87 @@
#!/usr/bin/env bash
list-prompts() {
- local prompts_dir="prompts"
- if [ -n "$1" ]; then
- prompts_dir="$1/prompts"
+ local repo_path="${1:-.}"
+
+ if [[ ! -d "$repo_path/.git" ]]; then
+ echo "Error: No .git directory found in $repo_path."
+ return 1
fi
-
- if [[ ! -d "$prompts_dir" ]]; then
- echo "No prompts directory found."
+
+ local worktree_path="$repo_path/tmp/prompt-log"
+
+ if [[ ! -d "$worktree_path" ]]; then
+ echo "No prompt-log worktree found."
return 0
fi
-
- local files=("$prompts_dir"/[0-9][0-9]_*.md)
-
- if [[ ${#files[@]} -eq 0 ]]; then
+
+ local files=("$worktree_path"/*.md)
+
+ if [[ ! -f "${files[0]}" ]]; then
echo "No prompt files found."
return 0
fi
-
- local max_id_len=2
- local max_title_len=10
+
+ local max_date_len=4
+ local max_title_len=5
local max_state_len=5
+ local max_commit_len=6
+
+ local -a rows
for file in "${files[@]}"; do
- local id=${file#"$prompts_dir"/}
- id=${id%%_*}
-
- local title=$(grep -m1 '^title:' "$file" | sed 's/^title:[[:space:]]*//; s/^"\(.*\)"$/\1/')
- local state=$(grep -m1 '^state:' "$file" | sed 's/^state:[[:space:]]*//; s/^"\(.*\)"$/\1/')
-
- if [[ ${#id} -gt max_id_len ]]; then
- max_id_len=${#id}
+ if [[ ! -f "$file" ]]; then
+ continue
fi
+ local title
+ title="$(grep -m1 '^title:' "$file" | sed 's/^title:[[:space:]]*//; s/^"\(.*\)"$/\1/; s/'"'"'\(.*\)'"'"'$/\1/')"
+
+ local state
+ state="$(grep -m1 '^state:' "$file" | sed 's/^state:[[:space:]]*//; s/^"\(.*\)"$/\1/; s/'"'"'\(.*\)'"'"'$/\1/')"
+
+ local filename
+ filename="$(basename "$file")"
+ local commit="${filename%%-*}"
+
+ local date
+ date="$(cd "$worktree_path" && git log --diff-filter=A --follow --format="%ad" --date=short -- "$filename" | tail -n 1)"
+
+ if [[ -z "$date" ]]; then
+ date="N/A"
+ fi
+
+ rows+=("$date|$title|$state|$commit")
+
+ if [[ ${#date} -gt max_date_len ]]; then
+ max_date_len=${#date}
+ fi
if [[ ${#title} -gt max_title_len ]]; then
max_title_len=${#title}
fi
-
if [[ ${#state} -gt max_state_len ]]; then
max_state_len=${#state}
fi
+ if [[ ${#commit} -gt max_commit_len ]]; then
+ max_commit_len=${#commit}
+ fi
done
- printf "| %-${max_id_len}s | %-${max_title_len}s | %-${max_state_len}s |\n" "id" "title" "state"
- printf "|-%s-|-%s-|-%s-|\n" "$(printf '%*s' "$max_id_len" '' | tr ' ' '-')" "$(printf '%*s' "$max_title_len" '' | tr ' ' '-')" "$(printf '%*s' "$max_state_len" '' | tr ' ' '-')"
+ printf "| %-${max_date_len}s | %-${max_title_len}s | %-${max_state_len}s | %-${max_commit_len}s |\n" "date" "title" "state" "commit"
+ printf "|-%s-|-%s-|-%s-|-%s-|\n" \
+ "$(printf '%*s' "$max_date_len" '' | tr ' ' '-')" \
+ "$(printf '%*s' "$max_title_len" '' | tr ' ' '-')" \
+ "$(printf '%*s' "$max_state_len" '' | tr ' ' '-')" \
+ "$(printf '%*s' "$max_commit_len" '' | tr ' ' '-')"
- for file in "${files[@]}"; do
- local id=${file#"$prompts_dir"/}
- id=${id%%_*}
+ local -a sorted
+ while IFS= read -r line; do
+ sorted+=("$line")
+ done < <(printf '%s\n' "${rows[@]}" | sort -t'|' -k1,1)
- local title=$(grep -m1 '^title:' "$file" | sed 's/^title:[[:space:]]*//; s/^"\(.*\)"$/\1/')
- local state=$(grep -m1 '^state:' "$file" | sed 's/^state:[[:space:]]*//; s/^"\(.*\)"$/\1/')
-
- printf "| %-${max_id_len}s | %-${max_title_len}s | %-${max_state_len}s |\n" "$id" "$title" "$state"
+ for row in "${sorted[@]}"; do
+ IFS='|' read -r date title state commit <<< "$row"
+ printf "| %-${max_date_len}s | %-${max_title_len}s | %-${max_state_len}s | %-${max_commit_len}s |\n" "$date" "$title" "$state" "$commit"
done
}
lp() {
diff --git a/bin/log-prompt b/bin/log-prompt
new file mode 100755
index 0000000..0b5d00d
--- /dev/null
+++ b/bin/log-prompt
@@ -0,0 +1,74 @@
+#!/usr/bin/env bash
+
+log-prompt() {
+ local repo_path="${1:-.}"
+
+ if [[ ! -d "$repo_path/.git" ]]; then
+ echo "Error: No .git directory found in $repo_path."
+ return 1
+ fi
+
+ local original_dir
+ original_dir="$(pwd)"
+ cd "$repo_path" || { echo "Cannot change to $repo_path"; return 1; }
+
+ local prompt_file="prompt.md"
+
+ if [[ ! -f "$prompt_file" ]]; then
+ echo "Error: $prompt_file not found in $repo_path."
+ cd "$original_dir" || true
+ return 1
+ fi
+
+ if [[ ! -d "tmp/prompt-log" ]] || ! git worktree list | grep -qF "$(pwd)/tmp/prompt-log"; then
+ echo "Creating prompt-log worktree."
+ if ! git show-ref --verify --quiet refs/heads/prompt-log; then
+ local current_branch
+ current_branch="$(git rev-parse --abbrev-ref HEAD)"
+ if [[ "$current_branch" == "prompt-log" ]]; then
+ echo "Error: Cannot create prompt-log worktree while on prompt-log branch."
+ cd "$original_dir" || true
+ return 1
+ fi
+ local empty_tree="4b825dc642cb6eb9a060e54bf8d69288fbee4904"
+ local orphan_commit
+ orphan_commit="$(echo "init: prompt-log branch" | git commit-tree "$empty_tree")"
+ git branch prompt-log "$orphan_commit"
+ fi
+ mkdir -p tmp
+ git worktree add "tmp/prompt-log" prompt-log
+ fi
+
+ local commit_hash
+ commit_hash="$(git rev-parse --short HEAD)"
+
+ local title
+ title="$(grep -m1 '^title:' "$prompt_file" | sed 's/^title:[[:space:]]*//; s/^"\(.*\)"$/\1/; s/'"'"'\(.*\)'"'"'$/\1/')"
+
+ if [[ -z "$title" ]]; then
+ echo "Error: Could not read title from $prompt_file frontmatter."
+ cd "$original_dir" || true
+ return 1
+ fi
+
+ local slug
+ slug=$(echo "$title" | tr '[:upper:]' '[:lower:]' | tr '.' '-' | tr ' ' '-' | tr -cd '[:alnum:]-')
+
+ local worktree_path="tmp/prompt-log"
+ local filename="${commit_hash}-${slug}.md"
+ local target_path="$worktree_path/$filename"
+
+ cp "$prompt_file" "$target_path"
+
+ (
+ cd "$worktree_path" || exit 1
+ git add "$filename"
+ git commit -m "feat: add prompt file" -m "$filename"
+ git push 2>/dev/null || echo "Warning: push failed."
+ ) || { echo "Error: Failed to store prompt."; cd "$original_dir" || true; return 1; }
+
+ cd "$original_dir" || true
+}
+lop() {
+ log-prompt "$@"
+}
diff --git a/bin/prompt-with-pi b/bin/prompt-with-pi
new file mode 100755
index 0000000..5415741
--- /dev/null
+++ b/bin/prompt-with-pi
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+prompt-with-pi() {
+ local prompt_file="${1:-prompt.md}"
+
+ if [[ ! -f "$prompt_file" ]]; then
+ echo "Error: Prompt file not found: $prompt_file"
+ return 1
+ fi
+
+ pi < "$prompt_file"
+}
+pwp() {
+ prompt-with-pi "$@"
+}
diff --git a/bin/show-prompt b/bin/show-prompt
new file mode 100755
index 0000000..850235c
--- /dev/null
+++ b/bin/show-prompt
@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+
+show-prompt() {
+ local commit=""
+ local repo_path="${2:-.}"
+
+ if [[ -n "$1" ]]; then
+ if [[ -n "$2" ]]; then
+ commit="$1"
+ elif [[ "$1" == */* ]] || [[ "$1" == "." ]]; then
+ repo_path="$1"
+ else
+ commit="$1"
+ fi
+ fi
+
+ if [[ ! -d "$repo_path/.git" ]]; then
+ echo "Error: No .git directory found in $repo_path."
+ return 1
+ fi
+
+ local worktree_path="$repo_path/tmp/prompt-log"
+
+ if [[ ! -d "$worktree_path" ]]; then
+ echo "No prompt-log worktree found. Run init-prompt-log first."
+ return 1
+ fi
+
+ local target_file
+
+ if [[ -z "$commit" ]]; then
+ if ! command -v fzf &> /dev/null; then
+ echo "Error: fzf is required for interactive selection."
+ return 1
+ fi
+
+ local selected
+ selected="$(
+ for f in "$worktree_path"/*.md; do
+ if [[ -f "$f" ]]; then
+ local f_title
+ f_title="$(grep -m1 '^title:' "$f" | sed 's/^title:[[:space:]]*//; s/^"\(.*\)"$/\1/; s/'"'"'\(.*\)'"'"'$/\1/')"
+ echo "$(basename "$f"): $f_title"
+ fi
+ done | fzf | cut -d: -f1
+ )"
+
+ if [[ -z "$selected" ]]; then
+ echo "No prompt selected."
+ return 0
+ fi
+
+ target_file="$worktree_path/$selected"
+ else
+ local matching_files=()
+ for f in "$worktree_path"/${commit}*.md; do
+ if [[ -f "$f" ]]; then
+ matching_files+=("$f")
+ fi
+ done
+
+ if [[ ${#matching_files[@]} -eq 0 ]]; then
+ echo "Error: No prompt file found starting with commit prefix '$commit'."
+ return 1
+ elif [[ ${#matching_files[@]} -gt 1 ]]; then
+ echo "Error: Ambiguous commit prefix '$commit'. Matches:"
+ printf '%s\n' "${matching_files[@]}"
+ return 1
+ fi
+
+ target_file="${matching_files[0]}"
+ fi
+
+ cat "$target_file"
+}
+shp() {
+ show-prompt "$@"
+}
diff --git a/prompts/convert-help-table-to-dynamic-width.md b/convert-help-table-to-dynamic-width.md
similarity index 100%
rename from prompts/convert-help-table-to-dynamic-width.md
rename to convert-help-table-to-dynamic-width.md
diff --git a/library.md b/library.md
index afbef5f..7b1c47c 100644
--- a/library.md
+++ b/library.md
@@ -290,16 +290,52 @@ The last parameter can be either a direct prompt string or a path to a text file
rows+=("update-changelog-with-llm|[num_lines]|Update CHANGELOG.md with changes from staged git diff using LLM.")
```
+### init-prompt-log
+
+```bash
+rows+=("init-prompt-log||Initialize prompt-log branch and worktree.")
+```
+
### create-prompt
```bash
-rows+=("create-prompt|[path]|Create a new prompt file from template.")
+rows+=("create-prompt|[repo-path]|Create prompt.md from template.")
+```
+
+### prompt-with-pi
+
+```bash
+rows+=("prompt-with-pi|[path]|Run pi with prompt.md.")
+```
+
+### log-prompt
+
+```bash
+rows+=("log-prompt|[repo-path]|Log prompt.md to prompt-log branch.")
```
### list-prompts
```bash
-rows+=("list-prompts|[path]|List all prompt files.")
+rows+=("list-prompts|[repo-path]|List prompts from prompt-log branch.")
+```
+
+### edit-prompt
+
+```bash
+rows+=("edit-prompt|[commit][repo-path]|Edit prompt directly in prompt-log worktree.")
+```
+
+### show-prompt
+
+```bash
+rows+=("show-prompt|[commit][repo-path]|Show prompt content from prompt-log.")
+```
+
+### convert-prompts-folder-to-prompt-log
+
+```bash
+rows+=("convert-prompts-folder-to-prompt-log|[repo-path]|Convert prompts folder to prompt-log branch.")
```
diff --git a/prompts/22_implement-prompt-log-commands.md b/prompt.md
similarity index 57%
rename from prompts/22_implement-prompt-log-commands.md
rename to prompt.md
index 9fb9126..f7eb4e8 100644
--- a/prompts/22_implement-prompt-log-commands.md
+++ b/prompt.md
@@ -1,21 +1,22 @@
---
title: "Implement prompt log commands"
-state: draft
-date_completed: YYYY-MM-DD
-model:
-input_tokens:
-output_tokens:
+author: "Janik von Rotz "
+state: completed
+date_completed: 2026-09-25
+model: moonshotai/Kimi-K2.6
+input_tokens: "~67000"
+output_tokens: "~280"
---
# Implement prompt log commands
-Note: @Clanker refers to the "ai agent" (you) who is working on this prompt.
+Note: @Clanker refers to the "ai agent" (you) who is working on this prompt file.
-@Clanker when working on this prompt, make sure to:
+@Clanker when working on this prompt file, make sure to:
- Read context and task section first
- Prepare a list of todos
-- Update the todo list while working on the task
+- Update the todo list while working on task
## Context
@@ -29,12 +30,10 @@ Instead of storing the prompts in the `prompts` folder I would like to store the
### Design decisions
-Settled points that aren't otherwise spelled out in the Commands section below:
-
- **Worktree lifecycle:** every command assumes the `prompt-log` git worktree exists and creates it on demand (same logic as `init-prompt-log`) if it doesn't — don't require the user to run `init-prompt-log` first every time.
- **Clipboard copy:** the clipboard-copy step in the current `create-prompt` is dropped entirely, not carried over.
- **`repo-path` argument:** wherever `[repo-path]` appears below, it means "operate on a different git repository" (worktree, branch, and `prompt.md` resolved relative to that path) — applied consistently, not just where spelled out under `create-prompt`.
-- **`prompt.md.template`:** remove the `${PROMPT_ID}` placeholder (no more numbering) and stop `create-prompt` from exporting `PROMPT_ID`; add the new `prompt_log_commit` frontmatter field, empty by default.
+- **`prompt.md.template`:** remove the `${PROMPT_ID}` placeholder (no more numbering) and stop `create-prompt` from exporting `PROMPT_ID`.
- **Session token/model capture:** out of scope for this task — `model`, `input_tokens`, `output_tokens` stay manually filled in.
### Commands
@@ -53,13 +52,9 @@ Runs the `pi` command and pipes the content of `prompt.md` as query. The harness
By default it uses the `prompt.md` of the current directory. It can also take a path to a prompt file.
-`store-prompt [repo-path]`
+`log-prompt [repo-path]`
-Reads the current commit hash (`git rev-parse --short HEAD`) of the project and the content of `prompt.md`.
-
-If `prompt.md`'s frontmatter has no `prompt_log_commit` set: creates a file named `-.md` in the `prompt-log` worktree, storing the content. Commits it with message title `feat: add prompt file` and the filename in the message body. Pushes `prompt-log` to the remote, warning (not failing) if the push doesn't succeed.
-
-If `prompt.md`'s frontmatter has `prompt_log_commit` set: looks up the prompt file whose name starts with that commit prefix (erroring if ambiguous), updates its content from `prompt.md`, commits with message `feat: update prompt file` and the filename in the body, pushes the same way, and clears `prompt_log_commit` from `prompt.md` on success.
+Reads the current commit hash (`git rev-parse --short HEAD`) of the project and the content of `prompt.md`. Creates a file named `-.md` in the `prompt-log` worktree, storing the content. Commits it with message title `feat: add prompt file` and the filename in the message body. Pushes `prompt-log` to the remote, warning (not failing) if the push doesn't succeed.
`list-prompts [repo-path]`
@@ -74,11 +69,15 @@ Rows are sorted by date.
`edit-prompt [commit] [repo-path]`
-If commit is not given, shows an `fzf` dialog of all files in the `prompt-log` branch, listing the frontmatter title. Selecting a file loads its content into `prompt.md` and opens it in `$EDITOR`. If commit is given, loads that target file directly and opens it in `$EDITOR`. Either way, writes the resolved commit hash into `prompt.md`'s `prompt_log_commit` frontmatter field. The user then runs `store-prompt` to push the update to the `prompt-log` branch.
+If commit is not given, shows an `fzf` dialog of all files in the `prompt-log` branch, listing the frontmatter title. Selecting a file opens it directly in `$EDITOR` within the `tmp/prompt-log` worktree. If commit is given, opens that target file directly in `$EDITOR`. After the editor closes, the change is committed with `feat: update prompt file` and pushed (warning on failure). The file is edited in place; `prompt.md` is not involved.
+
+`show-prompt [commit] [repo-path]`
+
+Similar to `edit-prompt` but outputs the prompt content directly to stdout instead of opening in `$EDITOR`. Accepts an optional commit prefix or shows an `fzf` dialog when no commit is given.
`convert-prompts-folder-to-prompt-log [repo-path]`
-Converts an existing `prompts` folder to the new format. For each file, looks up the commit on which it was first added (`git log --follow --diff-filter=A`) and commits it as `-.md` in the `prompt-log` branch, using the same commit-message convention as `store-prompt`. Files with no discoverable creation commit are reported and skipped. On success, deletes the old `prompts/` folder and its files.
+Converts an existing `prompts` folder to the new format. For each file, looks up the commit on which it was first added (`git log --follow --diff-filter=A`) and commits it as `-.md` in the `prompt-log` branch, using the same commit-message convention as `log-prompt`. Files with no discoverable creation commit are reported and skipped. On success, deletes the old `prompts/` folder and its files.
### Alias
@@ -87,38 +86,22 @@ Add an alias to each command:
- `init-prompt-log` → `ipl`
- `create-prompt` → `crp` (existing)
- `prompt-with-pi` → `pwp`
-- `store-prompt` → `sp`
+- `log-prompt` → `lop`
- `list-prompts` → `lp` (existing)
- `edit-prompt` → `ep`
+- `show-prompt` → `shp`
- `convert-prompts-folder-to-prompt-log` → `cpfpl`
-Check these don't collide with existing aliases elsewhere in the library before finalizing.
-
### Docs
-This is a major rehaul of the `prompt` commands. Update `library.md` with the commands in the LLM section.
-
-Then register the help row in the `task.template` file.
-
-### Test
-
-You can use this git project to test the commands. Make sure that a normal workflow works:
-
-```bash
-task init-prompt-log
-task create-prompt "Test Prompt"
-# Assume user runs 'task prompt-with-pi'
-# Assume user commits the resulting code changes
-task store-prompt
-task list-prompts
-task edit-prompt $commit_hash
-# Assume user edits and saves prompt.md
-task store-prompt
-task convert-prompts-folder-to-prompt-log
-```
+Update `library.md` with the commands in the LLM section. Register the help row in the `task.template` file.
## Worklog
-@Clanker Add a summary here once the task has been completed.
-
-@Clanker Set frontmatter state to completed and update date and model. If you have access to session info also add token count.
+- Created new bin scripts: `init-prompt-log`, `prompt-with-pi`, `log-prompt`, `edit-prompt`, `show-prompt`, `convert-prompts-folder-to-prompt-log`
+- Rewrote `bin/create-prompt` to output `prompt.md` directly with `author` from git log
+- Rewrote `bin/list-prompts` to read from `tmp/prompt-log` worktree
+- Updated `prompt.md.template` with `author` field
+- Added aliases and verified no collisions with existing aliases
+- Tested full workflow: init → create → store → list → edit → show → convert
+- Updated `library.md` and `task.template` with all new commands
diff --git a/prompt.md.template b/prompt.md.template
index fcf7904..64757d7 100644
--- a/prompt.md.template
+++ b/prompt.md.template
@@ -1,5 +1,6 @@
---
title: "$PROMPT_TITLE"
+author: "$PROMPT_AUTHOR"
state: draft
date_completed: YYYY-MM-DD
model:
@@ -27,6 +28,6 @@ Note: @Clanker refers to the "ai agent" (you) who is working on this prompt file
## Worklog
-@Clanker Add a summary here once the task is completed.
+@Clanker Add a summary here once the task has been completed.
@Clanker Set frontmatter state to completed and update date and model. If you have access to session info also add token count.
diff --git a/task.template b/task.template
index 607d68d..0847299 100755
--- a/task.template
+++ b/task.template
@@ -42,8 +42,14 @@ help-table() {
rows+=("commit-with-llm||Commit with llm generated commit message.")
rows+=("update-with-llm||Feed files matching glob to LLM and apply changes.")
rows+=("update-changelog-with-llm|[num_lines]|Update CHANGELOG.md with changes from staged git diff using LLM.")
- rows+=("create-prompt||Create a new prompt file from template.")
- rows+=("list-prompts|[path]|List all prompt files.")
+ rows+=("init-prompt-log||Initialize prompt-log branch and worktree.")
+ rows+=("create-prompt|[repo-path]|Create prompt.md from template.")
+ rows+=("prompt-with-pi|[path]|Run pi with prompt.md.")
+ rows+=("log-prompt|[repo-path]|Log prompt.md to prompt-log branch.")
+ rows+=("list-prompts|[repo-path]|List prompts from prompt-log branch.")
+ rows+=("edit-prompt|[commit][repo-path]|Edit prompt directly in prompt-log worktree.")
+ rows+=("show-prompt|[commit][repo-path]|Show prompt content from prompt-log.")
+ rows+=("convert-prompts-folder-to-prompt-log|[repo-path]|Convert prompts folder to prompt-log branch.")
rows+=("===Logging===| | ")
rows+=("log-error||Colored output for errors.")
rows+=("log-success||Colored output for success.")