loki-mode 9.56.0 → 9.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/completion-council.sh +79 -15
- package/autonomy/loki +9 -4
- package/autonomy/run.sh +22 -3
- package/dashboard/__init__.py +1 -1
- package/docs/dev/architecture-reference.md +99 -0
- package/docs/dev/project-structure.md +134 -0
- package/docs/dev/release-checklist.md +157 -0
- package/docs/dev/research-foundation.md +29 -0
- package/docs/dev/tmp-cleanup.md +157 -0
- package/docs/v10/BOARD.md +95 -76
- package/docs/v10/DECISIONS.md +14 -0
- package/docs/v10/METRICS.md +33 -0
- package/docs/v10/OPERATING-MODEL.md +47 -0
- package/docs/v10/PROGRESS.md +173 -0
- package/docs/v10/SWARM.md +24 -0
- package/loki-ts/dist/loki.js +2 -2
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Release checklist and local CI
|
|
2
|
+
|
|
3
|
+
Moved out of CLAUDE.md (S-78) to keep the root file short. Updated in this
|
|
4
|
+
pass to remove two items that `docs/v10/DECISIONS.md` D25 and
|
|
5
|
+
`docs/LOKI-10-BUILD-PROMPT.md` section 1 have superseded:
|
|
6
|
+
- `git add -A` in step 4 is replaced with staging by name (repo rule, always).
|
|
7
|
+
- Per-merge pushing is replaced by the release-train model (D25): batch
|
|
8
|
+
approved merges locally, push once per train, freeze main until Tests, Bun
|
|
9
|
+
Parity and Security Audit are all green on that exact SHA, then release.
|
|
10
|
+
"Wait for user approval before commit" from the old workflow is superseded
|
|
11
|
+
by the standing authorization in `docs/LOKI-10-BUILD-PROMPT.md` section 1
|
|
12
|
+
for sessions operating under that program; outside it, ask as normal.
|
|
13
|
+
|
|
14
|
+
## Local CI Before Every Push
|
|
15
|
+
|
|
16
|
+
**The FAST tier is the release gate. The FULL tier is not a blocker.**
|
|
17
|
+
|
|
18
|
+
Founder decision 2026-07-31: GitHub CI runs Tests in ~31s and Release in ~2min
|
|
19
|
+
via 4-way sharding. The local FULL tier takes ~27min with no sharding, too
|
|
20
|
+
slow for an hourly-or-faster release cadence.
|
|
21
|
+
|
|
22
|
+
- **Before push/release: `bash scripts/local-ci.sh`** (fast tier, default).
|
|
23
|
+
- **Do NOT block a release on `LOCAL_CI_TIER=full`.** Ship, let GitHub Actions
|
|
24
|
+
verify, and fix what it finds in the next release train.
|
|
25
|
+
- Run the FULL tier when diagnosing something specific, or on a quiet cycle,
|
|
26
|
+
not as a release precondition.
|
|
27
|
+
|
|
28
|
+
**Why the fast tier and not nothing.** Of seven real defects found on
|
|
29
|
+
2026-07-31, four were caught by the local gate ALONE. The sharpest is dist
|
|
30
|
+
freshness: CI never validates that the committed `loki-ts/dist/loki.js`
|
|
31
|
+
matches src; when that slipped, three releases shipped the wrong version.
|
|
32
|
+
|
|
33
|
+
**The packaged artifact is the blind spot (2026-08-01).** Everything works
|
|
34
|
+
from a git checkout, so no in-repo test and no GitHub CI job can see:
|
|
35
|
+
- quality-gate detector test files missing from npm's `files[]` (v8.38.0)
|
|
36
|
+
- committed `dist/loki.js` hardcoded to a stale version for 27 releases (v8.40.0)
|
|
37
|
+
- `npm pack` content checks that tolerate losing required artifacts (v9.11.0)
|
|
38
|
+
|
|
39
|
+
Rules that generalize past packaging:
|
|
40
|
+
1. A check that guards the shipped artifact must run in the FAST tier.
|
|
41
|
+
2. Assert each required thing individually, never a count.
|
|
42
|
+
3. Guard against vacuity (an empty capture that makes every assertion pass;
|
|
43
|
+
`npm pack`'s listing is on STDERR).
|
|
44
|
+
|
|
45
|
+
`LOCAL_CI_SHARDS` (default 4) controls local sharding; `LOCAL_CI_SERIAL=1`
|
|
46
|
+
forces serial for diagnosis.
|
|
47
|
+
|
|
48
|
+
After a release ships, run post-release distribution validation:
|
|
49
|
+
- npm: `npm pack loki-mode@<VERSION>`, untar, run `bash package/bin/loki version`
|
|
50
|
+
- Docker: `docker pull asklokesh/loki-mode:<VERSION>`, `docker run --rm <img> version`,
|
|
51
|
+
`doctor --json`, `status --json`
|
|
52
|
+
- Brew: WebFetch the live formula, verify version + sha256
|
|
53
|
+
- Both routes (Bun + LOKI_LEGACY_BASH=1) on each channel
|
|
54
|
+
|
|
55
|
+
Cleanup after every local-ci run and post-release validation uses
|
|
56
|
+
`loki_run_tmp_cleanup` (see `docs/dev/tmp-cleanup.md`).
|
|
57
|
+
|
|
58
|
+
## Release Workflow
|
|
59
|
+
|
|
60
|
+
**Step 0 (always first): `bash scripts/local-ci.sh`** -- pre-push gate.
|
|
61
|
+
|
|
62
|
+
### 1. Version Bump - ALL Files
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
VERSION # Single line: X.Y.Z
|
|
66
|
+
package.json # "version": "X.Y.Z"
|
|
67
|
+
SKILL.md # Header (line ~6) AND footer (last line)
|
|
68
|
+
Dockerfile # LABEL version= AND org.opencontainers.image.version (both, or it drifts)
|
|
69
|
+
Dockerfile.sandbox # Same two labels
|
|
70
|
+
plugins/loki-mode/.claude-plugin/plugin.json # "version": "X.Y.Z" (marketplace.json carries no version)
|
|
71
|
+
server.json # "version" AND packages[loki-mode].version (MCP registry manifest; enforced by tests/test-server-json-current.sh)
|
|
72
|
+
vscode-extension/package.json # DEPRECATED v7.2.0, no longer published; bump only if vendoring
|
|
73
|
+
CLAUDE.md # Version pointer, if present
|
|
74
|
+
dashboard/__init__.py # __version__ = "X.Y.Z"
|
|
75
|
+
mcp/__init__.py # __version__ = "X.Y.Z"
|
|
76
|
+
CHANGELOG.md # Add new version entry at top
|
|
77
|
+
docs/INSTALLATION.md # Version header
|
|
78
|
+
wiki/Home.md, wiki/_Sidebar.md, wiki/API-Reference.md
|
|
79
|
+
README.md, docker-compose.yml # Docker image tags (MAJOR/MINOR bumps)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 2. Build Dashboard Frontend
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
cd dashboard-ui && npm ci && npm run build:all && cd ..
|
|
86
|
+
ls -la dashboard/static/index.html # verify >100KB
|
|
87
|
+
```
|
|
88
|
+
`npm publish`'s `prepublishOnly` also triggers this build automatically.
|
|
89
|
+
|
|
90
|
+
### 3. Run Tests
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
bash -n autonomy/run.sh
|
|
94
|
+
bash -n autonomy/loki
|
|
95
|
+
python3 -c "import ast, os; [ast.parse(open(f'dashboard/{f}').read()) for f in os.listdir('dashboard') if f.endswith('.py')]"
|
|
96
|
+
python3 -c "import json; json.load(open('package.json')); print('JSON OK')"
|
|
97
|
+
cd dashboard-ui && npx playwright test && cd .. # requires dashboard on 57374
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 3a. Pre-Publish Validation (MANDATORY)
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npm pack --dry-run 2>&1 | grep -E "web-app/dist|dashboard/static" || echo "FAIL: expected files missing"
|
|
104
|
+
git ls-files web-app/dist/index.html | grep -q . || echo "FAIL: web-app/dist/ not tracked"
|
|
105
|
+
git ls-files dashboard/static/index.html | grep -q . || echo "FAIL: dashboard/static/ not tracked"
|
|
106
|
+
npm pack && npm install -g ./loki-mode-*.tgz
|
|
107
|
+
loki --version
|
|
108
|
+
loki web --no-open &
|
|
109
|
+
sleep 3
|
|
110
|
+
curl -s http://127.0.0.1:57374/ | grep -q "Loki" && echo "PASS: web app serves" || echo "FAIL"
|
|
111
|
+
curl -s http://127.0.0.1:57374/api/status | python3 -c "import json,sys; json.load(sys.stdin)" 2>/dev/null && echo "PASS: API responds" || echo "FAIL"
|
|
112
|
+
loki web stop
|
|
113
|
+
npm install -g loki-mode
|
|
114
|
+
rm -f loki-mode-*.tgz
|
|
115
|
+
```
|
|
116
|
+
If any check fails, do not release; fix the root cause first.
|
|
117
|
+
|
|
118
|
+
### 4. Commit and land (release-train model, D25)
|
|
119
|
+
|
|
120
|
+
Stage files by name (never `git add -A` or `git add .`), commit with the
|
|
121
|
+
repo-local `asklokesh` identity, no co-author. Batch approved merges locally;
|
|
122
|
+
push once per train (`git push origin main`); wait for Tests, Bun Parity and
|
|
123
|
+
Security Audit to go green on that exact SHA before bumping VERSION and
|
|
124
|
+
releasing. GitHub Actions then creates the tag, the GitHub Release, publishes
|
|
125
|
+
npm, builds/pushes Docker, and updates the Homebrew tap. Do not manually
|
|
126
|
+
create tags.
|
|
127
|
+
|
|
128
|
+
### 5. Verify ALL Distribution Channels
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
gh run list --limit 1 && gh run watch <run-id>
|
|
132
|
+
npm view loki-mode version
|
|
133
|
+
npm pack loki-mode --dry-run 2>&1 | grep dashboard/static
|
|
134
|
+
docker pull asklokesh/loki-mode:X.Y.Z && docker run --rm asklokesh/loki-mode:X.Y.Z loki version
|
|
135
|
+
brew update && brew info loki-mode
|
|
136
|
+
gh release view vX.Y.Z
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Distribution Channel Checklist
|
|
140
|
+
|
|
141
|
+
| Channel | Dashboard API | Dashboard Frontend | Memory System | Skills/References |
|
|
142
|
+
|---------|--------------------------|------------------------------|---------------|-------------------|
|
|
143
|
+
| npm | `dashboard/*.py` | `dashboard/static/index.html`| `memory/` | `skills/`, `references/` |
|
|
144
|
+
| Docker | `COPY dashboard/` | Built in Dockerfile or committed | `memory/` | `skills/`, `references/` |
|
|
145
|
+
| Homebrew| Full tarball | Full tarball | Full tarball | Full tarball |
|
|
146
|
+
| VSCode | DEPRECATED v7.2.0 -- no longer published | -- | -- | -- |
|
|
147
|
+
| Release | Skill-only zip | N/A | N/A | `references/` |
|
|
148
|
+
|
|
149
|
+
### Credentials (GitHub Secrets)
|
|
150
|
+
`NPM_TOKEN`, `DOCKERHUB_USERNAME` / `DOCKERHUB_TOKEN`, `HOMEBREW_TAP_TOKEN`.
|
|
151
|
+
|
|
152
|
+
## Testing
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
./benchmarks/run-benchmarks.sh humaneval --execute --loki
|
|
156
|
+
./benchmarks/run-benchmarks.sh swebench --execute --loki
|
|
157
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Research foundation
|
|
2
|
+
|
|
3
|
+
Moved out of CLAUDE.md (S-78) to keep the root file short. Content unchanged.
|
|
4
|
+
|
|
5
|
+
Built on 2025 research from three major AI labs:
|
|
6
|
+
|
|
7
|
+
**OpenAI:**
|
|
8
|
+
- Agents SDK (guardrails, tripwires, handoffs, tracing)
|
|
9
|
+
- AGENTS.md / Agentic AI Foundation (AAIF) standards
|
|
10
|
+
|
|
11
|
+
**Google DeepMind:**
|
|
12
|
+
- SIMA 2 (self-improvement, hierarchical reasoning)
|
|
13
|
+
- Google DeepMind Robotics (VLA models, planning)
|
|
14
|
+
- Dreamer 4 (world model training)
|
|
15
|
+
- Scalable Oversight via Debate
|
|
16
|
+
|
|
17
|
+
**Anthropic:**
|
|
18
|
+
- Constitutional AI (principles-based self-critique)
|
|
19
|
+
- Alignment Faking Detection (sleeper agent probes)
|
|
20
|
+
- Claude Code Best Practices (Explore-Plan-Code)
|
|
21
|
+
|
|
22
|
+
**Academic:**
|
|
23
|
+
- CONSENSAGENT (anti-sycophancy)
|
|
24
|
+
- GoalAct (hierarchical planning)
|
|
25
|
+
- A-Mem/MIRIX (memory systems)
|
|
26
|
+
- Multi-Agent Reflexion (MAR)
|
|
27
|
+
- NVIDIA ToolOrchestra (efficiency metrics)
|
|
28
|
+
|
|
29
|
+
See `references/openai-patterns.md`, `references/lab-research-patterns.md`, and `references/advanced-patterns.md`.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Temp directory and process cleanup (mandatory helpers)
|
|
2
|
+
|
|
3
|
+
Moved out of CLAUDE.md (S-78) to keep the root file short. Content unchanged.
|
|
4
|
+
CLAUDE.md still states the invariant; this file holds the runnable helpers.
|
|
5
|
+
|
|
6
|
+
## Test and Resource Cleanup (MANDATORY - NEVER SKIP)
|
|
7
|
+
|
|
8
|
+
**Before reporting ANY task as done, run ALL cleanup steps below. No exceptions.**
|
|
9
|
+
|
|
10
|
+
1. **Create one run-owned temp directory before the first temp write.** Keep
|
|
11
|
+
every archive, package extraction, log, PID file, and test fixture for the
|
|
12
|
+
task below this directory. Never use fixed names or shared globs under
|
|
13
|
+
`/tmp`.
|
|
14
|
+
|
|
15
|
+
2. **Stop only processes started by the current task.** Retain their exact PIDs
|
|
16
|
+
below `$LOKI_RUN_TMP` and signal those PIDs individually. Do not use
|
|
17
|
+
`pkill`, a shared-port sweep, or a name-pattern kill as cleanup.
|
|
18
|
+
|
|
19
|
+
3. **Remove only the validated run-owned directory.** Use the helpers below.
|
|
20
|
+
Cleanup fails closed unless the target is a direct child of the canonical
|
|
21
|
+
temp root, has the exact ownership marker created with it, is owned by the
|
|
22
|
+
current UID, still carries the private permissions the helper set (`700`
|
|
23
|
+
for the directory, `600` for the marker), is not a symlink, and is not a
|
|
24
|
+
Git worktree. Never replace this with a wildcard deletion under `/tmp` or
|
|
25
|
+
`$TMPDIR`.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
loki_run_tmp_create() {
|
|
29
|
+
local temp_root marker
|
|
30
|
+
|
|
31
|
+
if [ -n "${LOKI_RUN_TMP:-}" ]; then
|
|
32
|
+
printf '%s\n' "LOKI_RUN_TMP is already set; refusing to replace it" >&2
|
|
33
|
+
return 64
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
temp_root="$(cd "${TMPDIR:-/tmp}" 2>/dev/null && pwd -P)" || {
|
|
37
|
+
printf '%s\n' "Cannot resolve the temp root" >&2
|
|
38
|
+
return 64
|
|
39
|
+
}
|
|
40
|
+
LOKI_RUN_TMP="$(mktemp -d "${temp_root}/loki-run.XXXXXXXX")" || return 1
|
|
41
|
+
marker="${LOKI_RUN_TMP}/.loki-run-owned"
|
|
42
|
+
|
|
43
|
+
chmod 700 "$LOKI_RUN_TMP" || {
|
|
44
|
+
rmdir "$LOKI_RUN_TMP" 2>/dev/null || true
|
|
45
|
+
unset LOKI_RUN_TMP
|
|
46
|
+
return 1
|
|
47
|
+
}
|
|
48
|
+
if ! printf '%s\n' "$LOKI_RUN_TMP" >"$marker" || ! chmod 600 "$marker"; then
|
|
49
|
+
rm -f -- "$marker"
|
|
50
|
+
rmdir "$LOKI_RUN_TMP" 2>/dev/null || true
|
|
51
|
+
unset LOKI_RUN_TMP
|
|
52
|
+
return 1
|
|
53
|
+
fi
|
|
54
|
+
export LOKI_RUN_TMP
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# Read one numeric stat field portably. GNU uses -c, BSD uses -f, and each
|
|
58
|
+
# MISPARSES the other's flag: GNU -f means --file-system and still prints a
|
|
59
|
+
# filesystem block on stdout while exiting non-zero, so a bare `a || b`
|
|
60
|
+
# fallback captures that block and concatenates the real value onto it.
|
|
61
|
+
# Validate the captured value instead of trusting exit status or stream, so a
|
|
62
|
+
# usage string, a filesystem block, an empty result, or a concatenation of any
|
|
63
|
+
# of those is rejected on every platform.
|
|
64
|
+
loki_run_tmp_stat_field() {
|
|
65
|
+
local gnu_fmt="$1" bsd_fmt="$2" path="$3" value
|
|
66
|
+
|
|
67
|
+
value="$(stat -c "$gnu_fmt" -- "$path" 2>/dev/null)" || value=''
|
|
68
|
+
case "$value" in
|
|
69
|
+
'' | *[!0-9]*) value="$(stat -f "$bsd_fmt" -- "$path" 2>/dev/null)" || value='' ;;
|
|
70
|
+
esac
|
|
71
|
+
case "$value" in
|
|
72
|
+
'' | *[!0-9]*) return 1 ;;
|
|
73
|
+
esac
|
|
74
|
+
printf '%s\n' "$value"
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
loki_run_tmp_cleanup() {
|
|
78
|
+
local target temp_root marker marker_value target_real
|
|
79
|
+
local target_uid marker_uid target_mode marker_mode current_uid
|
|
80
|
+
|
|
81
|
+
target="${LOKI_RUN_TMP:-}"
|
|
82
|
+
[ -n "$target" ] || return 0
|
|
83
|
+
temp_root="$(cd "${TMPDIR:-/tmp}" 2>/dev/null && pwd -P)" || return 64
|
|
84
|
+
|
|
85
|
+
case "$target" in
|
|
86
|
+
"${temp_root}"/loki-run.*) ;;
|
|
87
|
+
*)
|
|
88
|
+
printf '%s\n' "Refusing cleanup outside the run-owned temp namespace: $target" >&2
|
|
89
|
+
return 64
|
|
90
|
+
;;
|
|
91
|
+
esac
|
|
92
|
+
[ "$(dirname -- "$target")" = "$temp_root" ] || return 64
|
|
93
|
+
[ -d "$target" ] && [ ! -L "$target" ] || return 64
|
|
94
|
+
|
|
95
|
+
marker="${target}/.loki-run-owned"
|
|
96
|
+
[ -f "$marker" ] && [ ! -L "$marker" ] || return 64
|
|
97
|
+
IFS= read -r marker_value <"$marker" || return 64
|
|
98
|
+
[ "$marker_value" = "$target" ] || return 64
|
|
99
|
+
|
|
100
|
+
current_uid="$(id -u)" || return 64
|
|
101
|
+
target_uid="$(loki_run_tmp_stat_field '%u' '%u' "$target")" || return 64
|
|
102
|
+
marker_uid="$(loki_run_tmp_stat_field '%u' '%u' "$marker")" || return 64
|
|
103
|
+
[ "$target_uid" = "$current_uid" ] && [ "$marker_uid" = "$current_uid" ] || return 64
|
|
104
|
+
|
|
105
|
+
# Refuse anything readable, writable, or executable by group or other. Only
|
|
106
|
+
# the low three permission digits are compared: GNU '%a' includes the
|
|
107
|
+
# setuid/setgid/sticky digit and BSD '%Lp' does not, and `mktemp -d` under a
|
|
108
|
+
# setgid temp root inherits g+s that a three-digit `chmod 700` preserves.
|
|
109
|
+
# Comparing the raw value against "700" would therefore read 2700 on Linux,
|
|
110
|
+
# refuse, and leak the very directory this helper exists to remove.
|
|
111
|
+
target_mode="$(loki_run_tmp_stat_field '%a' '%Lp' "$target")" || return 64
|
|
112
|
+
marker_mode="$(loki_run_tmp_stat_field '%a' '%Lp' "$marker")" || return 64
|
|
113
|
+
# Keep the last three digits, zero-padded, then require exactly 700/600.
|
|
114
|
+
target_mode="00${target_mode}"
|
|
115
|
+
marker_mode="00${marker_mode}"
|
|
116
|
+
[ "${target_mode#"${target_mode%???}"}" = "700" ] || return 64
|
|
117
|
+
[ "${marker_mode#"${marker_mode%???}"}" = "600" ] || return 64
|
|
118
|
+
|
|
119
|
+
target_real="$(cd "$target" 2>/dev/null && pwd -P)" || return 64
|
|
120
|
+
[ "$target_real" = "$target" ] || return 64
|
|
121
|
+
[ "$(dirname -- "$target_real")" = "$temp_root" ] || return 64
|
|
122
|
+
|
|
123
|
+
# A linked worktree has a .git file; a primary worktree has a .git
|
|
124
|
+
# directory. Refuse both, including a broken .git symlink.
|
|
125
|
+
if [ -e "${target}/.git" ] || [ -L "${target}/.git" ]; then
|
|
126
|
+
printf '%s\n' "Refusing to remove a Git worktree: $target" >&2
|
|
127
|
+
return 64
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
rm -rf -- "$target"
|
|
131
|
+
[ ! -e "$target" ] || return 1
|
|
132
|
+
unset LOKI_RUN_TMP
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
4. **Verify exact cleanup.** Confirm each recorded PID is gone and the saved
|
|
137
|
+
`$LOKI_RUN_TMP` path no longer exists. Do not scan or delete other users'
|
|
138
|
+
or runs' temp paths.
|
|
139
|
+
|
|
140
|
+
5. **Report cleanup status** to the user in the task completion message,
|
|
141
|
+
including only the explicit run-owned path and process IDs handled.
|
|
142
|
+
|
|
143
|
+
## Feedback Loop Requirement (before documenting a new feature)
|
|
144
|
+
|
|
145
|
+
1. **Verify it exists** - check files, run commands, test endpoints.
|
|
146
|
+
2. **Run feedback loop** - Task tool with Opus to review claims for accuracy.
|
|
147
|
+
3. **Be factual only** - never document features that don't work yet.
|
|
148
|
+
4. **Mark planned features** - use "Coming Soon" or "Planned" labels.
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
# Before documenting "npm install -g loki-mode"
|
|
152
|
+
npm view loki-mode # Does package exist on registry?
|
|
153
|
+
# Before documenting a CLI command
|
|
154
|
+
which loki && loki --help
|
|
155
|
+
# Before documenting a file path
|
|
156
|
+
ls -la path/to/file
|
|
157
|
+
```
|