SLOPSHOPPER

env-guard

git add/commit에 .env 파일이 들어가면 Bash 호출을 막는다

newguardtoast
v0.1.0no licenseupdated 2026-10-12alstjrwjd99/agent-memory/mods/env-guard
A shopper browsing a rack in a slop shop
README

agent-memory

에이전트의 경험 → 사실 → 판단 → 행동 규칙을 쌓는 메모리 시스템 + Claude Code mods. 설계: docs/DESIGN.md

윈도우(회사 PC)는 docs/SETUP-WINDOWS.md를 따르세요.

설치 (Mac / Windows 공통)

git clone <이 저장소> ~/workspace/agent-memory
claude plugin marketplace add ~/workspace/agent-memory
claude plugin install memory-events@agent-memory
claude plugin install memory-lens@agent-memory
claude plugin install env-guard@agent-memory

로컬 폴더 marketplace라 git pull 후 세션에서 /reload-plugins만 하면 반영됨.

기억 store (private)

git clone https://github.com/alstjrwjd99/memory-personal.git ~/workspace/memory-personal

작업 전후로 uv run amem sync (pull --rebase + push). events/는 PC 로컬에만 남음.

엔진 (amem)

cd engine
uv sync
uv run amem init --machine mac --personal ~/workspace/memory-personal          # 맥
uv run amem init --machine win-work --work C:\work\memory-work --personal ...  # 윈도우
uv run amem health
uv run amem promote            # events → episode (신호 있는 세션만 LLM 호출)
uv run amem reflect            # 판단 변화 제안 생성
uv run amem review             # 제안 확인
uv run amem apply <id> --only 1,3   /  uv run amem reject <id>
uv run amem export             # 확신도 높은 판단을 Claude Code 메모리로
uv run amem recall "질문" --cwd .   # 관련 기억 꺼내기 (memory-lens가 프롬프트마다 자동 호출)
uv run amem history <id>       # 한 기억의 변천 (versions + 확신도 + git diff)
uv run amem sync               # store git pull --rebase + push
uv run amem --store work ...   # 업무 store 대상

설정: ~/.config/agent-memory/config.yaml (윈도우: %USERPROFILE%\.config\agent-memory\config.yaml)

memory-events 설정 (/config 또는 settings.json pluginConfigs)

필드MacWindows(회사)
machinemacwin-work
defaultScopepersonalwork
personalStore~/workspace/memory-personal 절대경로(개인 store 경로)
workStore(비움)C:\...\memory-work
workPaths(비움)필요 시
Source 2 files
hooks/register.ts 16 lines
1import type { Register } from 'claude-code'
2import { findEnvFiles } from './guard.ts'
3
4export const register: Register = on => {
5  on('tool.call', { tool: 'Bash' }, ($, e, next) => {
6    const hits = findEnvFiles(e.command)
7    if (hits.length === 0) return next(e)
8
9    $.ui.toast(`env-guard: ${hits.join(', ')} 커밋 차단`)
10    return { deny: `${$.plugin.name}: .env 파일은 커밋 금지 (${hits.join(', ')}). .gitignore에 추가하고 해당 파일은 빼고 진행할 것.` }
11  }).catch(($, e, next) =>
12    // 가드 자체가 실패하면 안전하게 막는다
13    next.called ? next(e) : { deny: `${$.plugin.name}: 가드 실행 실패` },
14  )
15}
16
hooks/guard.ts 15 lines
1// git add/commit 명령에서 .env 계열 파일 인자를 찾는다 (.env.example 등 템플릿은 허용)
2const GIT_STAGE = /\bgit\s+(?:-C\s+\S+\s+)?(add|commit)\b/
3const ENV_FILE = /(^|[\/\\])\.env(\.[\w.-]+)?$/
4const TEMPLATE = /\.(example|sample|template|dist)$/
5
6export function findEnvFiles(command: string): string[] {
7  // && ; | 로 이어진 명령을 쪼개서 git add/commit 구간만 본다
8  return command
9    .split(/&&|\|\||;|\|/)
10    .filter(part => GIT_STAGE.test(part))
11    .flatMap(part => part.trim().split(/\s+/))
12    .map(token => token.replace(/^['"]|['"]$/g, ''))
13    .filter(token => ENV_FILE.test(token) && !TEMPLATE.test(token))
14}
15