claudecode/skills/setup/SKILL.md
Setup Awareness Memory — check local daemon, authenticate via browser, and configure credentials.
npx skillsauth add edwin-hao-ai/awareness-sdk setupInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Setup Awareness Memory: check local daemon status, optionally authenticate via browser, select a memory, and write credentials to settings.json.
Cloud API base URL: https://awareness.market/api/v1 Local daemon URL: http://localhost:37800
First check if the local Awareness daemon is running:
curl -sf http://localhost:37800/healthz 2>/dev/null && echo "DAEMON:RUNNING" || echo "DAEMON:NOT_RUNNING"
Get daemon status:
curl -sf http://localhost:37800/api/v1/status 2>/dev/null || echo "{}"
Tell the user:
Awareness local daemon is running!
Status: [show memory_id, mode, etc. from status response]
MCP URL: http://localhost:37800/mcp
Your local memory is ready to use.
Then ask: "Want to connect to Awareness Cloud for sync and sharing? (yes/no)"
Check if user has existing cloud credentials (same logic as before):
Read the current environment variables AWARENESS_API_KEY and AWARENESS_MEMORY_ID.
If both exist AND AWARENESS_API_KEY starts with aw_ AND is NOT the placeholder aw_your-api-key-here,
and AWARENESS_MEMORY_ID is NOT your-memory-id-here:
/awareness-memory:session-start instead.Run:
cat ~/.awareness/credentials.json 2>/dev/null
If the file exists and contains a valid api_key (starts with aw_):
api_key and api_base values.If no credentials found at all:
Awareness Memory is not configured. You have two options:
1. Start local daemon: npx @awareness-sdk/local start
(Run this in a separate terminal, then re-run /awareness-memory:setup)
2. Connect to cloud: Continue with browser authentication below
Which option? (local/cloud) [cloud]:
npx @awareness-sdk/local start in another terminal and re-run setup. Stop here.Run the entire auth flow in a single Bash command. This is critical — do NOT poll in a loop with separate Bash calls.
Run this exact script (substituting nothing — it is self-contained):
python3 -c "
import os, urllib.request, json, subprocess, sys, time, platform
API = 'https://awareness.market/api/v1'
# --- headless detection (F-035) ---
# On SSH / Docker / Codespaces / no-TTY hosts we must not try to open
# a browser — the user is reading this via the Claude CLI on a remote
# host and needs to click the URL on a different device.
def is_headless():
flag = os.environ.get('AWARENESS_HEADLESS', '').lower()
if flag in ('1','true','yes','on'): return True
if flag in ('0','false','no','off'): return False
if any(os.environ.get(k) for k in ('SSH_CONNECTION','SSH_CLIENT','SSH_TTY')): return True
if os.environ.get('CODESPACES','').lower() == 'true': return True
if os.environ.get('GITPOD_WORKSPACE_ID'): return True
if os.environ.get('CLOUD_SHELL','').lower() == 'true': return True
if platform.system() == 'Linux' and not os.environ.get('DISPLAY') and not os.environ.get('WAYLAND_DISPLAY'): return True
if not sys.stdout.isatty(): return True
return False
HEADLESS = is_headless()
# --- init ---
req = urllib.request.Request(API + '/auth/device/init', data=b'{}',
headers={'Content-Type':'application/json'}, method='POST')
try:
resp = json.load(urllib.request.urlopen(req, timeout=15))
except Exception as e:
print('ERROR:NETWORK:' + str(e)); sys.exit(1)
dc = resp['device_code']
uc = resp['user_code']
intv = resp.get('interval', 5)
ttl = resp.get('expires_in', 900)
print('USER_CODE:' + uc)
print('HEADLESS:' + ('1' if HEADLESS else '0'))
print('TTL:' + str(ttl))
sys.stdout.flush()
# --- open browser (skip on headless) ---
url = 'https://awareness.market/cli-auth?code=' + uc
if HEADLESS:
print('BROWSER:SKIPPED:' + url)
else:
try:
if platform.system() == 'Darwin':
subprocess.run(['open', url], check=True, capture_output=True)
elif platform.system() == 'Windows':
subprocess.run(['start', '', url], shell=True, check=True, capture_output=True)
else:
subprocess.run(['xdg-open', url], check=True, capture_output=True)
print('BROWSER:OPENED')
except Exception:
print('BROWSER:FAILED:' + url)
sys.stdout.flush()
# --- poll (up to ~14 min, aligned with backend TTL 900s) ---
max_polls = max(40, ttl // max(intv,1))
for i in range(1, max_polls + 1):
time.sleep(intv)
try:
preq = urllib.request.Request(API + '/auth/device/poll',
data=json.dumps({'device_code': dc}).encode(),
headers={'Content-Type':'application/json'}, method='POST')
pr = json.load(urllib.request.urlopen(preq, timeout=15))
except Exception:
if i % 4 == 0: print('POLL_ERROR:' + str(i))
continue
st = pr.get('status','')
if st == 'approved':
print('APPROVED:' + pr['api_key'])
sys.exit(0)
elif st == 'expired':
print('EXPIRED'); sys.exit(1)
if i % 4 == 0:
print('WAITING:' + str(i) + '/' + str(max_polls))
sys.stdout.flush()
print('TIMEOUT'); sys.exit(1)
"
Timeout for this Bash call: 840000 ms (14 minutes, aligned with F-035 backend TTL=900s).
The script prints structured lines. Parse them:
| Output prefix | Meaning | Action |
|---------------|---------|--------|
| USER_CODE:{code} | The human-readable auth code | Show to user (see message below) |
| HEADLESS:0 or HEADLESS:1 | Whether host is headless (SSH/Docker/no-TTY) | Tailor instructions: on headless host, tell user to open URL on a second device |
| TTL:{seconds} | Backend code lifetime (default 900 = 15 min) | Use in expiry message |
| BROWSER:OPENED | Browser opened successfully | No action needed |
| BROWSER:SKIPPED:{url} | Headless host — no browser attempt | Tell user to open the URL on any device with a browser |
| BROWSER:FAILED:{url} | Could not open browser | Tell user to open the URL manually |
| WAITING:{n}/{max} | Still polling | Silently continue waiting |
| POLL_ERROR:{n} | Network blip during poll | Ignore unless many in a row |
| APPROVED:{api_key} | Success! | Extract the api_key, proceed to Step 3 |
| EXPIRED | Device code expired (15 min backend TTL) | Tell user to run /awareness-memory:setup again |
| TIMEOUT | All polls exhausted, still pending | Ask user: keep waiting / start over / cancel |
| ERROR:NETWORK:{msg} | Cannot reach server at all | Tell user to check network connection |
As soon as you see the USER_CODE: line in the output, tell the user:
Your authorization code is: {user_code}
A browser window should open. Please:
1. Sign in (or create an account) in the browser
2. Confirm the code matches: {user_code}
3. Click "Authorize CLI"
Waiting for authorization...
If you see BROWSER:FAILED:{url}, also add:
Could not open browser automatically. Please open this URL:
{url}
Ask the user:
After getting the api_key:
mkdir -p ~/.awareness && printf '{"api_key":"%s","api_base":"https://awareness.market/api/v1"}\n' '{api_key}' > ~/.awareness/credentials.json && chmod 600 ~/.awareness/credentials.json
Verify the obtained API key works. Run:
curl -s -w "\nHTTP_STATUS:%{http_code}" https://awareness.market/api/v1/memories -H "Authorization: Bearer {api_key}"
Parse the output:
HTTP_STATUS: line at the end./awareness-memory:setup again."Use the JSON response from Step 3 (already fetched). Parse it as a JSON array. Each memory object has at least id and name.
If Step 3 was skipped (reusing credentials from 1b), fetch the list now:
curl -s https://awareness.market/api/v1/memories -H "Authorization: Bearer {api_key}"
If user has 0 memories:
If user has 1+ memories:
Your memories:
1. {name_1}
2. {name_2}
...
N+1. Create new memory
Select a memory (1-{N+1}) [1]:
Handle user's choice:
id and nameAsk the user: "Describe what this memory is for (e.g. 'My startup project backend development'):"
If user gives empty input, use: "General-purpose memory for development workflow".
Create via wizard — run as a single Bash command:
python3 -c "
import urllib.request, json, sys
API = 'https://awareness.market/api/v1'
KEY = '{api_key}'
DESC = '''USER_DESCRIPTION_HERE'''
headers = {'Authorization': 'Bearer ' + KEY, 'Content-Type': 'application/json'}
# Step 1: wizard
wiz_body = json.dumps({'owner_id':'','locale':'en','messages':[{'role':'user','content': DESC}],'draft':{}}).encode()
wiz_req = urllib.request.Request(API + '/wizard/memory_designer', data=wiz_body, headers=headers, method='POST')
try:
wiz_resp = json.load(urllib.request.urlopen(wiz_req, timeout=30))
except Exception as e:
print('ERROR:WIZARD:' + str(e)); sys.exit(1)
payload = wiz_resp.get('plan',{}).get('create_payload')
if not payload:
print('ERROR:NO_PAYLOAD'); sys.exit(1)
# Step 2: create memory
create_req = urllib.request.Request(API + '/memories', data=json.dumps(payload).encode(), headers=headers, method='POST')
try:
mem = json.load(urllib.request.urlopen(create_req, timeout=15))
except Exception as e:
print('ERROR:CREATE:' + str(e)); sys.exit(1)
print('CREATED:' + mem['id'] + ':' + mem.get('name','New Memory'))
"
Replace USER_DESCRIPTION_HERE with the user's description (escape any single quotes by replacing ' with '\'').
Parse output:
CREATED:{id}:{name} → success, use these valuesERROR:WIZARD:... or ERROR:CREATE:... → tell user: "Could not create memory automatically. Create one at https://awareness.market/dashboard, then run /awareness-memory:setup again."The skill variable ${CLAUDE_SKILL_DIR} points to this skill's directory (skills/setup/).
The plugin's settings.json is two levels up:
SETTINGS_PATH="${CLAUDE_SKILL_DIR}/../../settings.json"
Verify it exists:
[ -f "${CLAUDE_SKILL_DIR}/../../settings.json" ] && echo "SETTINGS_PATH:${CLAUDE_SKILL_DIR}/../../settings.json" || echo "SETTINGS_PATH:NOT_FOUND"
SETTINGS_PATH:NOT_FOUND → tell user: "Could not find plugin settings. Make sure the plugin is installed: /plugin marketplace add edwin-hao-ai/Awareness-SDK then /plugin install awareness-memory@awareness". Stop here.If local daemon mode (from Step 1, user chose not to connect cloud):
Use the Write tool (NOT Bash) to write the settings.json file. Content:
{
"env": {
"AWARENESS_MCP_URL": "http://localhost:37800/mcp",
"AWARENESS_AGENT_ROLE": "builder_agent"
}
}
If cloud mode (completed Steps 2-4):
Use the Write tool (NOT Bash) to write the settings.json file. Content:
{
"env": {
"AWARENESS_MCP_URL": "https://awareness.market/mcp",
"AWARENESS_MEMORY_ID": "{memory_id}",
"AWARENESS_API_KEY": "{api_key}",
"AWARENESS_AGENT_ROLE": "builder_agent"
}
}
For local daemon mode:
Setup complete! (Local mode)
MCP URL: http://localhost:37800/mcp
Mode: Local-first
Your memory is stored locally. To sync with cloud later, run /awareness-memory:setup again.
To activate, restart Claude Code and then run:
/awareness-memory:session-start
For cloud mode:
Setup complete! (Cloud mode)
API Key: {first 10 chars of api_key}...
Memory: {memory_name} ({memory_id})
MCP URL: https://awareness.market/mcp
To activate, restart Claude Code and then run:
/awareness-memory:session-start
Clearly explain: a restart is needed because MCP connections are established at session start using the env vars from settings.json. The new credentials won't take effect until the next session.
| Scenario | Action |
|----------|--------|
| Local daemon running | Show status, offer cloud connection |
| Local daemon not running, no credentials | Offer local start or cloud auth |
| Network unreachable (init fails) | Stop with clear message, suggest checking connection |
| Browser won't open | Show manual URL from BROWSER:FAILED output |
| User never authorizes (TIMEOUT) | Ask: keep waiting (re-run script) or cancel |
| Device code expired (EXPIRED) | Tell user to re-run /awareness-memory:setup |
| API key invalid (401 on verify) | Tell user to re-run setup |
| No memories + wizard fails | Direct user to web dashboard |
| settings.json not found | Tell user to install plugin first |
| User gives invalid memory choice | Re-ask up to 3 times, then default to first |
python3 -c for consistency (do NOT use jq or other tools)device_code to the user — only show user_codetools
Initialize memory session, load project context, and create a session_id for tracking.
tools
Save current session progress to Awareness memory as a batch of structured steps.
testing
Search Awareness memory for past implementations, decisions, or relevant context.
tools
End the current Awareness memory session and save final progress.