filelu-register
Register a FileLu.com account from just an email address and save the credentials
to YAML — that's the whole job by default. The browser is only needed for the
signup form (reCAPTCHA), so the agent fills it, asks the human to solve the
captcha and click the activation email, and stops there. Optionally, if the user
wants to drive FileLu over its HTTP API afterwards, a second short browser visit
logs back in and captures the API key from the account page.
Why this skill is shaped the way it is
FileLu's signup page is protected by Google reCAPTCHA v2, so a plain HTTP
POST to /register is rejected — there is no signup API. A real browser (the
user's own Chrome via browser-harness) is the only path that can render the
challenge. The human is already at the machine to click the activation email, so
having them solve the captcha in the same window costs nothing and avoids
depending on a paid captcha-solving service.
The signup is the only step that must be a browser visit. If the user later
wants the API key (optional), one more login-and-scrape visit captures it; after
that every file operation runs over the documented https://filelu.com/api/*
endpoints with no browser at all.
Prerequisites
- The
browser-harness skill / CLI must be available. If it isn't installed,
stop and tell the user to install it first — this skill cannot work without it.
- The user's local Chrome must allow remote debugging. If
browser-harness --doctor reports it can't connect, follow the browser-harness skill's
connection instructions (enable remote debugging in chrome://inspect). The
harness will launch Chrome itself if it isn't running.
- Python 3 (for the bundled helper). No third-party packages required.
browser-harness js() convention
js(expr) evaluates JavaScript and returns its value. Two legal forms — pick
one per call, never mix:
- Single expression that already evaluates to the value you want:
js("(document.body.innerText||'').slice(0,800)").
- Statements (variables, loops, multiple steps): wrap the whole thing in an
IIFE that returns the result, e.g.
js("(function(){ ...; return x; })()").
A bare return or let/const at the top level throws SyntaxError: Illegal return statement — the harness evaluates your string as an expression, it does
not silently wrap statements in a function. Every multi-line js(...) in this
skill already follows the IIFE pattern; keep new ones the same.
Never put a newline character inside a js() string literal. An escaped
\n or \\n in the heredoc survives the shell and Python layers but lands as a
raw newline inside the JS source sent to V8, which rejects a literal line break
inside '...'/"..." with SyntaxError: Invalid or unexpected token. To join
or split lines, use ' | ' / ';' separators or String.fromCharCode(10)
instead — never '\n'/'\\n' inside the JS expression.
The flow
Phase 1 (register) and Phase 2 (the user activates) are the default — that's
the whole job. Phase 3 (connect methods: API, S3, WebDAV, Rclone, Rsync, FTP,
Chrome, MCP, email) is optional, and within it each item is independently
optional — only set up what the user asks for. Offer Phase 3 once the account is
activated and let the user opt in per method.
Phase 1 — Register the account (browser)
Collect the email. The only required input is the email. Accept optional
overrides: username, password, region (one of global, us-east,
eu-central, ap-southeast, me-central; default global). Decide where to
save the account YAML — default <repo>/filelu-accounts/<safe-email>.yaml
(see Storage below); let the user override.
Generate credentials. Run the helper to produce a FileLu-legal username
(derived from the email local-part + a random suffix) and a strong password,
then write the initial YAML with status: pending_activation. Use the
SKILL_DIR substitution below — the skill directory is the one containing
this SKILL.md:
SKILL_DIR="<path to this skill>"
python "$SKILL_DIR/scripts/filelu_account.py" gen \
--email "USER@EXAMPLE.COM" [--username "$U"] [--password "$P"] [--region global] \
| python "$SKILL_DIR/scripts/filelu_account.py" save --path "filelu-accounts/foo.yaml"
Read it back so you have the exact username/password for the form:
python "$SKILL_DIR/scripts/filelu_account.py" load --path "filelu-accounts/foo.yaml"
Open the signup page in the user's Chrome via browser-harness. The first
navigation is always new_tab, not goto_url:
browser-harness <<'PY'
new_tab("https://filelu.com/register.html")
wait_for_load()
print(page_info())
PY
Fill the form. FileLu uses a plain Bootstrap form. Set values directly on
the named inputs and dispatch input + change so any listener and the
CheckForm validator see them. This is more reliable than synthesizing
keystrokes and works through the AX-tree/coordinate fallback when needed:
browser-harness <<'PY'
js("""
(function(){
function setVal(name, val) {
const el = document.querySelector('[name="' + name + '"]');
if (!el) throw new Error('field not found: ' + name);
el.value = val;
el.dispatchEvent(new Event('input', {bubbles: true}));
el.dispatchEvent(new Event('change', {bubbles: true}));
return el.value;
}
setVal('usr_login', 'USERNAME_FROM_YAML');
setVal('usr_email', 'USER@EXAMPLE.COM');
setVal('usr_password', 'PASSWORD_FROM_YAML');
setVal('usr_region', 'global');
return document.querySelector('[name=usr_login]').value
+ '|' + document.querySelector('[name=usr_email]').value;
})()
""")
PY
Always echo the values back out of the DOM afterward — never assume the write
took. Validation rules from FileLu's CheckForm: username 4–32 chars
[a-zA-Z0-9_-], password 4–32 chars, email must be a valid address. The
helper already enforces these.
Handle reCAPTCHA — this needs the human. Detect the captcha and whether
it's already solved:
browser-harness <<'PY'
print(js("String(!!document.querySelector('.g-recaptcha')) "
"+ '|' + (document.querySelector('[name=\"g-recaptcha-response\"]')||{}).value"))
PY
- If the response token is already non-empty (rare — happens when the session
is trusted), skip to step 6.
- Otherwise stop and tell the user plainly: "I've filled the form. Please
solve the reCAPTCHA in the Chrome window I opened, then tell me 'done'."
Wait for the user to confirm. Then re-check the response token; if still
empty, ask again. Do not loop rapidly — the challenge needs a real
human click and spamming checks won't help.
Submit. Click the real submit button — do not call
form.submit(), which bypasses the CheckForm validator and loses the
g-recaptcha-response. FileLu's signup button is a plain same-origin
<button type="submit">Create Account</button>, so clicking it through JS
triggers onsubmit (the validator) just like a real click and is far more
robust than hunting for button text in the AX tree:
browser-harness <<'PY'
print(js("""
(function(){
const b = document.querySelector('button[type=submit]')
|| document.querySelector('[type=submit]');
if (!b) throw new Error('submit button not found');
b.click();
return 'clicked';
})()
"""))
wait_for_load()
print(page_info())
PY
If the JS click is swallowed (rare — shadow DOM or an overlay intercepting
it), fall back to a coordinate click on the button's box model via
cdp("DOM.getBoxModel", backendNodeId=...) → click_at_xy(cx, cy), the way
the browser-harness skill describes.
Confirm success. After submit, expect a redirect to the logged-in area or
a "check your email" / activation notice. Grep the page for known failure
text (Invalid, already, captcha, exist) before declaring victory:
browser-harness <<'PY'
print(js("(document.body.innerText||'').slice(0,800)"))
PY
On failure, surface the exact message to the user and stop — do not retry
blindly. If the username was taken, generate a new one (gen again with an
explicit --username) and redo steps 4–6.
Persist state. The YAML was already written in step 2; if anything
changed (e.g. you picked a different username on a collision), re-save. Leave
status: pending_activation.
Hand off to the user for activation. Tell them clearly, with the email
address shown, then stop — Phase 1 is done:
Account created. Activation email sent to USER@EXAMPLE.COM. Open it and
click the verification link, then tell me "activated".
Wait for the user to confirm activation (Phase 2). Don't poll the browser.
Don't presume the connect-methods step — that's optional and only runs if the
user asks for it after activation.
Phase 2 — Activation (the user, not you)
This phase happens entirely outside the agent: the user opens their email and
clicks FileLu's verification link. Your only job is to wait for confirmation.
When the user says "activated" / "done" / "clicked", mark the account
status: activated (helper update --status activated) — the job is done.
Then offer the optional next step: "Want to set up any connect methods (API,
S3, WebDAV, Rclone, Rsync, FTP, Chrome extension, MCP, email) so you can drive
FileLu without the browser? Say which ones." Only run Phase 3 if they say yes.
If they report the activation link didn't work, have them paste any error —
FileLu activation failures are usually an expired link or an already-activated
account.
Phase 3 — Connect methods (optional; each item independent)
After activation the account is already usable via the web UI. Run Phase 3 only
if the user wants to drive FileLu through one of its connect methods — API,
S3, WebDAV, Rclone, Rsync, FTP/FTPS, Chrome extension, MCP, or the upload-by-email
address. Every item is independently optional; capture only what the user asks
for. None of this can go through the HTTP API — FileLu's /api/* only does
file/folder ops, it cannot enable protocols or generate keys — so this whole phase
is browser work in the one logged-in tab. Full per-method detail (enable params,
copy-button IDs, static host/port, YAML key names) lives in
references/connect.md; the orchestration is here.
Present the menu and let the user pick. List what each method gives them
and ask which to set up (multi-select). Don't assume any of them:
Which connect methods do you want enabled? Pick any combination:
- API —
?key= access to /api/* (uploads, file/folder CRUD, account info)
- S3 (S5) — S3-compatible endpoint + access/secret + default bucket name
- WebDAV — WebDAV URL + password
- Rclone — Rclone key for the
filelu backend
- Rsync — rsync-over-SSH (
rsync.filelu.com:2222, uses account password)
- FTP / FTPS —
ftp.filelu.com:21 / :990 (uses account password)
- Chrome extension — extension key for the FileLu uploader add-on
- MCP — token for ChatGPT/Claude/Cursor etc. via
https://mcp.filelu.com/mcp
- Email — the
up_XXXX@filelu.cloud upload-by-email address
Confirm you're logged in, then open My Account and read the session token
(every enable link needs it):
browser-harness <<'PY'
goto_url("https://filelu.com/?op=my_account")
wait_for_load()
print(js("(function(){ var t=document.querySelector('input[name=token]'); return t?t.value:''; })()"))
PY
Keep that token as $TOKEN for every enable in this phase. Re-read it if you
re-login.
For each chosen method, enable + capture + save following
references/connect.md. The shared enable pattern is a
GET — the toggle's own onclick is location='?op=my_account&<PARAM>=<VAL>&token=...':
browser-harness <<'PY'
goto_url("https://filelu.com/?op=my_account&<PARAM>=<VAL>&token=" + TOKEN)
wait_for_load()
PY
Then read the revealed value (generated keys appear in a ClipboardJS copy button
that only exists post-enable — read its data-clipboard-target) and persist it:
python "$SKILL_DIR/scripts/filelu_account.py" update \
--path "filelu-accounts/foo.yaml" \
--set "connect_<method>_<field>=VALUE" \
--set "connect_<method>_enabled_at=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
Per-method enable params and what to capture (cheat sheet — see connect.md for
the full table):
- API —
generate_api_key=1 → capture from #copyApiKey; mirror to
--api-key too so verify works, then run verify --key.
- S3 —
s3_enable=1 → read endpoint / region / default bucket name /
access key / secret from the #s3 pane.
- WebDAV —
webdav_enable=1 → URL + password from the #webdav pane.
- Rclone —
turn_on_rclone=1 → key from #copyRcloneKey.
- Rsync —
rsync_enable=1 → no secret (account password); record static
rsync.filelu.com:2222.
- FTP/FTPS — enable is the inverted toggle
ftp_disable=0; no secret
(account password); record static ftp.filelu.com port 21 / FTPS 990.
- Chrome —
turn_on_chrome=1 → key from #copyCEKey.
- MCP — not a toggle: fill the
#mcp form (mcp_name,
mcp_allowed_fld_id=0, mcp_expires_days, perms) and submit
generate_mcp_token; capture token + server URL. Free tier = one
read-only token.
- Email — no enable needed; read
up_XXXX@filelu.cloud from the #email
pane.
Verify the high-value captures. For the API key, the canonical check is
verify --key, which hits /api/account/info. For S3/WebDAV/Rclone/MCP there's
no public verify endpoint — a non-empty value read from the right pane element
is the best available evidence; if a value looks truncated or empty, re-read the
pane DOM (js("document.getElementById('<pane>').innerText")) and re-capture.
Report what was set up. Summarize per method, give the YAML path, and for
each enabled method give one copy-pasteable usage line (e.g. an rclone config
block, a curl for the API, an mcp URL for ChatGPT). Keep the browser tab
open only if the user wants it.
Storage
One YAML file per account, default location filelu-accounts/<safe-email>.yaml
where <safe-email> is the email with @ → _at_ and non [a-z0-9_.-] → _.
The schema (flat, hand-editable, valid YAML):
email: "user@example.com"
username: "user_abc123"
password: "..."
region: "global"
status: "activated" # draft | pending_activation | activated | api_ready | failed
registered_at: "2026-08-07T19:06:41Z"
activated_at: "2026-08-07T19:10:00Z"
api_key: "..." # top-level mirror of connect_api_key, used by `verify`
api_verified_at: "2026-08-07T19:11:00Z"
notes: ""
# Phase 3 captures land flat with a connect_ prefix (see references/connect.md):
connect_api_key: ""
connect_s3_bucket: ""
connect_ftp_host: ""
connect_mcp_token: ""
# ...any connect_<method>_<field> the user asked for
If the user prefers one combined file, honor it — just keep the same schema.
## Common failure modes
- **reCAPTCHA never solves / keeps challenging:** the session looks automated.
Ask the user to solve it themselves in the opened window; if it loops, suggest
they log into Google in that Chrome profile first (raises trust) and retry.
- **"Username already taken":** regenerate with `gen --email ... --username
<new>` and re-fill only the username field, then re-submit. Don't change the
email.
- **Activation email never arrives:** have the user check spam, then use the
FileLu "resend activation" link on the login page (drive it via browser-harness
the same way as login). Don't proceed to Phase 3 until activated — login will
just fail.
- **`verify` says `Invalid auth` after API capture:** the key didn't copy
cleanly or the toggle didn't actually flip on. Re-read the `#api` pane DOM
(`js("document.getElementById('api').innerText")`), re-enable via
`generate_api_key=1`, and re-capture from `#copyApiKey`'s target.
- **A connect value reads empty post-enable:** the ClipboardJS copy button
wasn't in the DOM yet (it's injected after enable). Make sure the enable GET
actually reloaded the page, then query the pane by id and read the value
element directly. See [`references/connect.md`](references/connect.md).
## After registration: using the account
Once activated, the account works via the **web UI** with no extra setup. If
Phase 3 captured connect methods, the YAML holds everything needed to use them
without a browser:
- **HTTP API** (if `connect_api_key` / `api_key` is set): see
[`references/api.md`](references/api.md) — uploads, file/folder CRUD, account
info, all via `?key=`.
- **S3 / WebDAV / Rclone / Rsync / FTP / MCP / Email**: connection details and
usage snippets are in [`references/connect.md`](references/connect.md).
1---2name: filelu-register3description: Automate FileLu.com account registration from just an email address. Use this skill whenever the user wants to sign up for / create / register a FileLu (filelu.com) account, open a FileLu account for an email address, or automate FileLu onboarding — even if they don't say "register" explicitly (e.g. "set me up on FileLu with this email", "open a filelu account for ..."). It drives the browser signup (reCAPTCHA forces a real browser), generates FileLu-legal credentials, saves them to YAML, and hands off to the human for the email activation click. When the user also wants to go pure-API afterwards, it optionally logs in once more to capture the API key from the account page.4---56# filelu-register78Register a FileLu.com account from just an email address and save the credentials9to YAML — that's the whole job by default. The browser is only needed for the10signup form (reCAPTCHA), so the agent fills it, asks the human to solve the11captcha and click the activation email, and stops there. Optionally, if the user12wants to drive FileLu over its HTTP API afterwards, a second short browser visit13logs back in and captures the API key from the account page.1415## Why this skill is shaped the way it is1617FileLu's signup page is protected by **Google reCAPTCHA v2**, so a plain HTTP18`POST` to `/register` is rejected — there is no signup API. A real browser (the19user's own Chrome via `browser-harness`) is the only path that can render the20challenge. The human is already at the machine to click the activation email, so21having them solve the captcha in the same window costs nothing and avoids22depending on a paid captcha-solving service.2324The signup is the only step that *must* be a browser visit. If the user later25wants the API key (optional), one more login-and-scrape visit captures it; after26that every file operation runs over the documented `https://filelu.com/api/*`27endpoints with no browser at all.2829## Prerequisites3031- The `browser-harness` skill / CLI must be available. If it isn't installed,32 stop and tell the user to install it first — this skill cannot work without it.33- The user's local Chrome must allow remote debugging. If `browser-harness34 --doctor` reports it can't connect, follow the browser-harness skill's35 connection instructions (enable remote debugging in `chrome://inspect`). The36 harness will launch Chrome itself if it isn't running.37- Python 3 (for the bundled helper). No third-party packages required.3839## browser-harness `js()` convention4041`js(expr)` evaluates JavaScript and returns its value. Two legal forms — pick42one per call, never mix:4344- **Single expression** that already evaluates to the value you want:45 `js("(document.body.innerText||'').slice(0,800)")`.46- **Statements** (variables, loops, multiple steps): wrap the whole thing in an47 IIFE that returns the result, e.g. `js("(function(){ ...; return x; })()")`.4849A bare `return` or `let`/`const` at the top level throws `SyntaxError: Illegal50return statement` — the harness evaluates your string as an expression, it does51not silently wrap statements in a function. Every multi-line `js(...)` in this52skill already follows the IIFE pattern; keep new ones the same.5354**Never put a newline character inside a `js()` string literal.** An escaped55`\n` or `\\n` in the heredoc survives the shell and Python layers but lands as a56raw newline inside the JS source sent to V8, which rejects a literal line break57inside `'...'`/`"..."` with `SyntaxError: Invalid or unexpected token`. To join58or split lines, use `' | '` / `';'` separators or `String.fromCharCode(10)`59instead — never `'\n'`/`'\\n'` inside the JS expression.6061## The flow6263Phase 1 (register) and Phase 2 (the user activates) are the default — that's64the whole job. Phase 3 (connect methods: API, S3, WebDAV, Rclone, Rsync, FTP,65Chrome, MCP, email) is **optional**, and within it each item is independently66optional — only set up what the user asks for. Offer Phase 3 once the account is67activated and let the user opt in per method.6869### Phase 1 — Register the account (browser)70711. **Collect the email.** The only required input is the email. Accept optional72 overrides: `username`, `password`, `region` (one of `global`, `us-east`,73 `eu-central`, `ap-southeast`, `me-central`; default `global`). Decide where to74 save the account YAML — default `<repo>/filelu-accounts/<safe-email>.yaml`75 (see *Storage* below); let the user override.76772. **Generate credentials.** Run the helper to produce a FileLu-legal username78 (derived from the email local-part + a random suffix) and a strong password,79 then write the initial YAML with `status: pending_activation`. Use the80 `SKILL_DIR` substitution below — the skill directory is the one containing81 this `SKILL.md`:82 ```bash83 SKILL_DIR="<path to this skill>"84 python "$SKILL_DIR/scripts/filelu_account.py" gen \85 --email "USER@EXAMPLE.COM" [--username "$U"] [--password "$P"] [--region global] \86 | python "$SKILL_DIR/scripts/filelu_account.py" save --path "filelu-accounts/foo.yaml"87 ```88 Read it back so you have the exact username/password for the form:89 ```bash90 python "$SKILL_DIR/scripts/filelu_account.py" load --path "filelu-accounts/foo.yaml"91 ```92933. **Open the signup page** in the user's Chrome via browser-harness. The first94 navigation is always `new_tab`, not `goto_url`:95 ```bash96 browser-harness <<'PY'97 new_tab("https://filelu.com/register.html")98 wait_for_load()99 print(page_info())100 PY101 ```1021034. **Fill the form.** FileLu uses a plain Bootstrap form. Set values directly on104 the named inputs and dispatch `input` + `change` so any listener and the105 `CheckForm` validator see them. This is more reliable than synthesizing106 keystrokes and works through the AX-tree/coordinate fallback when needed:107 ```bash108 browser-harness <<'PY'109 js("""110 (function(){111 function setVal(name, val) {112 const el = document.querySelector('[name="' + name + '"]');113 if (!el) throw new Error('field not found: ' + name);114 el.value = val;115 el.dispatchEvent(new Event('input', {bubbles: true}));116 el.dispatchEvent(new Event('change', {bubbles: true}));117 return el.value;118 }119 setVal('usr_login', 'USERNAME_FROM_YAML');120 setVal('usr_email', 'USER@EXAMPLE.COM');121 setVal('usr_password', 'PASSWORD_FROM_YAML');122 setVal('usr_region', 'global');123 return document.querySelector('[name=usr_login]').value124 + '|' + document.querySelector('[name=usr_email]').value;125 })()126 """)127 PY128 ```129 Always echo the values back out of the DOM afterward — never assume the write130 took. Validation rules from FileLu's `CheckForm`: username 4–32 chars131 `[a-zA-Z0-9_-]`, password 4–32 chars, email must be a valid address. The132 helper already enforces these.1331345. **Handle reCAPTCHA — this needs the human.** Detect the captcha and whether135 it's already solved:136 ```bash137 browser-harness <<'PY'138 print(js("String(!!document.querySelector('.g-recaptcha')) "139 "+ '|' + (document.querySelector('[name=\"g-recaptcha-response\"]')||{}).value"))140 PY141 ```142 - If the response token is already non-empty (rare — happens when the session143 is trusted), skip to step 6.144 - Otherwise **stop and tell the user plainly**: *"I've filled the form. Please145 solve the reCAPTCHA in the Chrome window I opened, then tell me 'done'."*146 Wait for the user to confirm. Then re-check the response token; if still147 empty, ask again. Do **not** loop rapidly — the challenge needs a real148 human click and spamming checks won't help.1491506. **Submit.** Click the real submit button — do **not** call151 `form.submit()`, which bypasses the `CheckForm` validator and loses the152 `g-recaptcha-response`. FileLu's signup button is a plain same-origin153 `<button type="submit">Create Account</button>`, so clicking it through JS154 triggers `onsubmit` (the validator) just like a real click and is far more155 robust than hunting for button text in the AX tree:156 ```bash157 browser-harness <<'PY'158 print(js("""159 (function(){160 const b = document.querySelector('button[type=submit]')161 || document.querySelector('[type=submit]');162 if (!b) throw new Error('submit button not found');163 b.click();164 return 'clicked';165 })()166 """))167 wait_for_load()168 print(page_info())169 PY170 ```171 If the JS click is swallowed (rare — shadow DOM or an overlay intercepting172 it), fall back to a coordinate click on the button's box model via173 `cdp("DOM.getBoxModel", backendNodeId=...)` → `click_at_xy(cx, cy)`, the way174 the browser-harness skill describes.1751767. **Confirm success.** After submit, expect a redirect to the logged-in area or177 a "check your email" / activation notice. Grep the page for known failure178 text (`Invalid`, `already`, `captcha`, `exist`) before declaring victory:179 ```bash180 browser-harness <<'PY'181 print(js("(document.body.innerText||'').slice(0,800)"))182 PY183 ```184 On failure, surface the exact message to the user and stop — do not retry185 blindly. If the username was taken, generate a new one (`gen` again with an186 explicit `--username`) and redo steps 4–6.1871888. **Persist state.** The YAML was already written in step 2; if anything189 changed (e.g. you picked a different username on a collision), re-save. Leave190 `status: pending_activation`.1911929. **Hand off to the user for activation.** Tell them clearly, with the email193 address shown, then stop — Phase 1 is done:194 > Account created. Activation email sent to **USER@EXAMPLE.COM**. Open it and195 > click the verification link, then tell me "activated".196197 Wait for the user to confirm activation (Phase 2). Don't poll the browser.198 Don't presume the connect-methods step — that's optional and only runs if the199 user asks for it after activation.200201### Phase 2 — Activation (the user, not you)202203This phase happens entirely outside the agent: the user opens their email and204clicks FileLu's verification link. Your only job is to wait for confirmation.205When the user says "activated" / "done" / "clicked", mark the account206`status: activated` (helper `update --status activated`) — **the job is done.**207Then offer the optional next step: *"Want to set up any connect methods (API,208S3, WebDAV, Rclone, Rsync, FTP, Chrome extension, MCP, email) so you can drive209FileLu without the browser? Say which ones."* Only run Phase 3 if they say yes.210If they report the activation link didn't work, have them paste any error —211FileLu activation failures are usually an expired link or an already-activated212account.213214### Phase 3 — Connect methods *(optional; each item independent)*215216After activation the account is already usable via the web UI. Run Phase 3 only217if the user wants to drive FileLu through one of its **connect methods** — API,218S3, WebDAV, Rclone, Rsync, FTP/FTPS, Chrome extension, MCP, or the upload-by-email219address. Every item is **independently optional**; capture only what the user asks220for. **None of this can go through the HTTP API** — FileLu's `/api/*` only does221file/folder ops, it cannot enable protocols or generate keys — so this whole phase222is browser work in the one logged-in tab. Full per-method detail (enable params,223copy-button IDs, static host/port, YAML key names) lives in224[`references/connect.md`](references/connect.md); the orchestration is here.2252261. **Present the menu and let the user pick.** List what each method gives them227 and ask which to set up (multi-select). Don't assume any of them:228 > Which connect methods do you want enabled? Pick any combination:229 > - **API** — `?key=` access to `/api/*` (uploads, file/folder CRUD, account info)230 > - **S3 (S5)** — S3-compatible endpoint + access/secret + default bucket name231 > - **WebDAV** — WebDAV URL + password232 > - **Rclone** — Rclone key for the `filelu` backend233 > - **Rsync** — rsync-over-SSH (`rsync.filelu.com:2222`, uses account password)234 > - **FTP / FTPS** — `ftp.filelu.com:21` / `:990` (uses account password)235 > - **Chrome extension** — extension key for the FileLu uploader add-on236 > - **MCP** — token for ChatGPT/Claude/Cursor etc. via `https://mcp.filelu.com/mcp`237 > - **Email** — the `up_XXXX@filelu.cloud` upload-by-email address2382392. **Confirm you're logged in**, then open My Account and read the session token240 (every enable link needs it):241 ```bash242 browser-harness <<'PY'243 goto_url("https://filelu.com/?op=my_account")244 wait_for_load()245 print(js("(function(){ var t=document.querySelector('input[name=token]'); return t?t.value:''; })()"))246 PY247 ```248 Keep that token as `$TOKEN` for every enable in this phase. Re-read it if you249 re-login.2502513. **For each chosen method, enable + capture + save** following252 [`references/connect.md`](references/connect.md). The shared enable pattern is a253 GET — the toggle's own `onclick` is `location='?op=my_account&<PARAM>=<VAL>&token=...'`:254 ```bash255 browser-harness <<'PY'256 goto_url("https://filelu.com/?op=my_account&<PARAM>=<VAL>&token=" + TOKEN)257 wait_for_load()258 PY259 ```260 Then read the revealed value (generated keys appear in a ClipboardJS copy button261 that only exists post-enable — read its `data-clipboard-target`) and persist it:262 ```bash263 python "$SKILL_DIR/scripts/filelu_account.py" update \264 --path "filelu-accounts/foo.yaml" \265 --set "connect_<method>_<field>=VALUE" \266 --set "connect_<method>_enabled_at=$(date -u +%Y-%m-%dT%H:%M:%SZ)"267 ```268 Per-method enable params and what to capture (cheat sheet — see connect.md for269 the full table):270 - **API** — `generate_api_key=1` → capture from `#copyApiKey`; mirror to271 `--api-key` too so `verify` works, then run `verify --key`.272 - **S3** — `s3_enable=1` → read endpoint / region / **default bucket name** /273 access key / secret from the `#s3` pane.274 - **WebDAV** — `webdav_enable=1` → URL + password from the `#webdav` pane.275 - **Rclone** — `turn_on_rclone=1` → key from `#copyRcloneKey`.276 - **Rsync** — `rsync_enable=1` → no secret (account password); record static277 `rsync.filelu.com:2222`.278 - **FTP/FTPS** — enable is the **inverted** toggle `ftp_disable=0`; no secret279 (account password); record static `ftp.filelu.com` port `21` / FTPS `990`.280 - **Chrome** — `turn_on_chrome=1` → key from `#copyCEKey`.281 - **MCP** — not a toggle: fill the `#mcp` form (`mcp_name`,282 `mcp_allowed_fld_id=0`, `mcp_expires_days`, perms) and submit283 `generate_mcp_token`; capture token + server URL. Free tier = one284 **read-only** token.285 - **Email** — no enable needed; read `up_XXXX@filelu.cloud` from the `#email`286 pane.2872884. **Verify the high-value captures.** For the API key, the canonical check is289 `verify --key`, which hits `/api/account/info`. For S3/WebDAV/Rclone/MCP there's290 no public verify endpoint — a non-empty value read from the right pane element291 is the best available evidence; if a value looks truncated or empty, re-read the292 pane DOM (`js("document.getElementById('<pane>').innerText")`) and re-capture.2932945. **Report what was set up.** Summarize per method, give the YAML path, and for295 each enabled method give one copy-pasteable usage line (e.g. an `rclone` config296 block, a `curl` for the API, an `mcp` URL for ChatGPT). Keep the browser tab297 open only if the user wants it.298299## Storage300301One YAML file per account, default location `filelu-accounts/<safe-email>.yaml`302where `<safe-email>` is the email with `@` → `_at_` and non `[a-z0-9_.-]` → `_`.303The schema (flat, hand-editable, valid YAML):304305```yaml306email: "user@example.com"307username: "user_abc123"308password: "..."309region: "global"310status: "activated" # draft | pending_activation | activated | api_ready | failed311registered_at: "2026-08-07T19:06:41Z"312activated_at: "2026-08-07T19:10:00Z"313api_key: "..." # top-level mirror of connect_api_key, used by `verify`314api_verified_at: "2026-08-07T19:11:00Z"315notes: ""316# Phase 3 captures land flat with a connect_ prefix (see references/connect.md):317connect_api_key: ""318connect_s3_bucket: ""319connect_ftp_host: ""320connect_mcp_token: ""321# ...any connect_<method>_<field> the user asked for322323If the user prefers one combined file, honor it — just keep the same schema.324325## Common failure modes326327- **reCAPTCHA never solves / keeps challenging:** the session looks automated.328 Ask the user to solve it themselves in the opened window; if it loops, suggest329 they log into Google in that Chrome profile first (raises trust) and retry.330- **"Username already taken":** regenerate with `gen --email ... --username331 <new>` and re-fill only the username field, then re-submit. Don't change the332 email.333- **Activation email never arrives:** have the user check spam, then use the334 FileLu "resend activation" link on the login page (drive it via browser-harness335 the same way as login). Don't proceed to Phase 3 until activated — login will336 just fail.337- **`verify` says `Invalid auth` after API capture:** the key didn't copy338 cleanly or the toggle didn't actually flip on. Re-read the `#api` pane DOM339 (`js("document.getElementById('api').innerText")`), re-enable via340 `generate_api_key=1`, and re-capture from `#copyApiKey`'s target.341- **A connect value reads empty post-enable:** the ClipboardJS copy button342 wasn't in the DOM yet (it's injected after enable). Make sure the enable GET343 actually reloaded the page, then query the pane by id and read the value344 element directly. See [`references/connect.md`](references/connect.md).345346## After registration: using the account347348Once activated, the account works via the **web UI** with no extra setup. If349Phase 3 captured connect methods, the YAML holds everything needed to use them350without a browser:351- **HTTP API** (if `connect_api_key` / `api_key` is set): see352 [`references/api.md`](references/api.md) — uploads, file/folder CRUD, account353 info, all via `?key=`.354- **S3 / WebDAV / Rclone / Rsync / FTP / MCP / Email**: connection details and355 usage snippets are in [`references/connect.md`](references/connect.md).