# Spec Sheet — Log End

**What you are building:** A project-scoped skill that closes the currently-open entry in a per-session time-log folder by writing an end time and a session description passed as the command argument.

> Bracketed [PLACEHOLDERS] are yours to fill in for your own project. This skill uses no credentials; if your variant ever needs one, supply it from your own secret store, never inline in the SKILL.md.

## 1. Purpose

Maintain a verifiable log of work sessions. A companion "log-start" skill opens an entry with a start time and a blank end field; this skill closes that entry with the current time plus a short description of what was done. The log is committed to a git remote, so the push timestamp serves as a tamper-resistant record. The discipline only works if entries are closed at the moment work ends, with a real description — this skill makes that a one-line action.

## 2. Activation

- **Skill name:** `log-end` (or `[your-prefix]-log-end`).
- **Description (what makes the model auto-trigger):** state plainly that it records the END of a [PROJECT] work session by updating today's open time-log entry with an end time and a description provided as the argument. Name the explicit trigger: the user runs `/log-end <description>` or asks to "log the end of a session" / "close out the work log." Make clear a description argument is expected. Keep it distinct from the log-start skill's description so the two don't collide.
- **Argument:** a free-text description of the session, taken as everything after `/log-end`.

## 3. Inputs and preconditions

- **Required:** a one-line description argument.
- **Precondition:** an open entry for today exists in `[time-log-dir]/` — a file whose end field has no value yet, created by the log-start skill.
- The skill reads no other user input and asks no questions.

## 4. Outputs and side effects

- The open entry file is edited in place:
  - the end field is filled with the current time;
  - the description is appended as a paragraph below the metadata block;
  - the title is optionally rewritten from a generic default to a short topic derived from the description.
- A single confirmation line is printed (filename + close time).
- No new file is ever created by this skill. No other entry is touched. The environment field is left unchanged.

## 5. Environment and dependencies

- A repo-root (or project-root) folder, here `[time-log-dir]/` (example: `time-log/`), holding one markdown file per session.
- A companion **log-start** skill that creates entries in the format this skill expects.
- A shell with `date` available.
- A git remote the folder is pushed to, if you want the verifiable-timestamp property (push the folder as part of your normal session-wrap flow). Not required for the skill to function locally.
- **Entry format this skill reads and writes** (must match what log-start emits):
  ```markdown
  # YYYY-MM-DD — [default-topic or rewritten topic]

  - Start: HH:MM
  - End: HH:MM        ← this skill fills the value
  - Environment: [environment-label]

  [description paragraph]   ← this skill appends here
  ```
  An entry is "open" when the `End:` line has nothing after the colon.

## 6. Procedure

1. **No-argument guard (run first).** If invoked with no description, write nothing and reply with exactly one line directing the user to re-run with a description plus a short example. Then stop — do not run any step below.
2. **Get current date and time** via `date '+%Y-%m-%d %H:%M'`. Keep the resulting string; you will paste it literally.
3. **Locate today's open entry.** List the time-log folder for files matching today's date, e.g. `ls [time-log-dir]/YYYY-MM-DD-*.md`, substituting the literal date string from step 2. Inspect each match's end field; the open one has no value after the colon. **Do not use `$( … )` command substitution** — paste the literal date instead (see Guardrails for why).
4. **No open entry → stop.** If none is found, reply that there is no open session for today (suggest the user may have skipped log-start, or may be logging retroactively) and stop without creating a file.
5. **Multiple open entries → pick latest start.** If more than one open entry exists, close the one with the latest start time and warn briefly that the others remain open and may need manual fixing.
6. **Update the chosen entry:**
   - Fill the end field: `- End: HH:MM` with the current time.
   - Append the description as a new paragraph immediately after the blank line that ends the metadata block (the block ends after the environment line).
   - Optionally rewrite the title from the generic default to `# YYYY-MM-DD — <topic>`, where `<topic>` is a short noun phrase from the first 4–6 words of the description. If the description is too generic for a clean topic, leave the title as-is.
   - Leave the environment field exactly as set at start. Touch no other file.
7. **Confirm in one line**, e.g. `Logged session end: [time-log-dir]/YYYY-MM-DD-HHMM.md (closed at HH:MM)`. Do not elaborate.

## 7. Edge cases and failure handling

- **No description argument:** the guard in step 1 — write nothing, ask for a re-run, stop.
- **No open entry today:** reply and stop; never fabricate or create an entry.
- **Multiple open entries:** close the latest-start one, warn about the rest; do not try to close all of them.
- **Generic description:** skip the title rewrite rather than forcing an awkward topic.
- **Retroactive / different-environment sessions:** out of scope for the automated path; the user edits by hand.

## 8. Guardrails / hard rules

- Ask the user no questions. Use only the description argument.
- Never modify the environment field.
- Never modify any entry other than today's single open one. Create no new files.
- Never run with an empty description — half-closed, undescribed entries defeat the log's purpose.
- **Avoid `$( … )` in the instructions' shell commands.** In Claude Code, any command containing `$()` triggers an approval prompt even when an allow-rule would otherwise match — which interrupts a flow meant to be frictionless. Paste literal values, or inject command output before the model sees it, instead.
- Reply with a single confirmation line; no commentary.

## 9. Acceptance criteria

- Running `/log-end <description>` against a folder with exactly one open entry for today: the end field is filled with the current time, the description appears as a paragraph below the metadata, and (when the description allows) the title becomes a short topic. The confirmation line names the file and close time.
- Running `/log-end` with no argument: no file is changed and the reply is the single re-run prompt.
- Running `/log-end <description>` with no open entry for today: no file is created and the reply states no open session was found.
- With two open entries, only the latest-start one is closed and the reply warns about the other.
- The environment field and every other file in the folder are byte-for-byte unchanged.
- No command the skill runs contains `$()`.

## 10. Adapt to your setup

- Replace `time-log/` with `[time-log-dir]` and "[PROJECT]" with your project's name throughout.
- Decide your environment labels; the skill only preserves whatever start wrote, so this is really a log-start concern.
- Decide whether you want the verifiable-timestamp property; if so, ensure the folder is committed and pushed to a remote, and document that the push timestamp is the record. If not, drop that framing.
- Keep this skill's read/write format identical to your log-start skill's write format — the two are a matched pair.
- If your harness does not penalize `$()`, you may simplify the date-substitution step, but literal-paste is harmless either way.

---

```markdown
---
name: log-end
description: Record the end of a [PROJECT] work session. Updates today's open time-log entry with an end time and a description provided as the argument. Use when the user runs /log-end <description>.
---

# Log session end

Closes the open entry in `[time-log-dir]/` by adding the end time and a description.

## Argument required

# State that a description argument is mandatory; give one example invocation.
# If invoked with no argument: write nothing, reply with a single re-run prompt + example, then STOP.

## What to do (when a description is provided)

# 1. Get current date+time: date '+%Y-%m-%d %H:%M'
# 2. List today's entries (literal date, NO $()); find the one whose End: line is empty.
# 3. No open entry -> reply "no open session for today" and stop.
# 4. Multiple open entries -> close the latest-start one; warn about the others.
# 5. Update: fill `- End: HH:MM`; append description paragraph after the metadata block;
#    optionally rewrite title to a short topic from the first 4-6 words of the description.
# 6. Reply with one confirmation line (filename + close time). Do not elaborate.

## Important

# - Ask nothing. Use only the description argument.
# - Do not change the Environment field. Do not modify any other entry. Create no new files.
# - Avoid $() in shell commands (approval-prompt friction); paste literal values.
```
