[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CD107WMZPVY06HP7VGPH0V":3,"skill-same:01M6CD107WMZPVY06HP7VGPH0V":124},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":42,"linkOnly":43,"markdownContent":44,"markdownBody":45,"frontMatter":46,"refName":49,"commitSha":50,"skillDirectory":51,"forksCount":52,"repositoryHtmlUrl":53,"repositoryHomepageUrl":6,"ownerHtmlUrl":54,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":55,"install":56,"resources":69},"01M6CD107WMZPVY06HP7VGPH0V","jujutsu-vcs",null,"Guide AI agents to use Jujutsu (jj) for version control. Covers core concepts, daily workflows, Git compatibility, conflict resolution, and collaboration with GitHub. Use this skill when working with jj repositories or when the user wants to use Jujutsu instead of Git.","cercova-studios\u002F10x-swe","cercova-studios","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F217108198?v=4","01M6CCYGHXTH80N3BXRW6KESTE","Cercova Studios","01M6CCYGPADH5MJDR0VNNR775C",1,"MIT","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fjujutsu-vcs\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41],"jujutsu","jujutsu vcs","daily","repositories","when","for","concepts","with","control","resolution","conflict","conflict resolution","github","version","use","guide","user","jj","git","core","collaboration","workflows","ai agents","2026-11-10 10:12:30",false,"---\n\ndescription: Bootstrap a Liferay Workspace, download and verify the bundle, set up auth verifiers, and complete first login bootstrap. Use when the user is starting fresh, when the server appears down or unreachable, when gradle.properties or bundles\u002F is missing, or when the user asks to set up, initialize, or scaffold a workspace.\nname: workspace-init\n\n---\n\n# Workspace Init\n\nStand up a working Liferay Workspace from zero, or diagnose a workspace that looks uninitialized. Covers `blade init`, bundle download, license setup, BasicAuth verifier, server start, and first login bootstrap.\n\n## When to Invoke\n\n- The user asks to set up, initialize, or scaffold a workspace, or asks for setup help.\n- The server appears down or unreachable.\n- The workspace looks uninitialized — missing `bundles\u002F`, or missing `gradle.properties`.\n- Do not run through all steps for a returning user whose server is already running.\n\n> **Note:** These rules apply to local workspace initialization and must not be used to configure higher environments (UAT\u002FProd).\n\n## Workflow\n\n### Version and Tooling Check\n\n- **Check version**: read `liferay.workspace.product` in `gradle.properties`.\n- **Verify tooling**: check that `blade` (`blade --version`) and Java (`javac -version`) are installed. If missing, provide installation steps.\n- **DXP License**: if `liferay.workspace.product` contains `dxp`, a license file is required. Liferay identifies license files by XML content, not filename — check `bundles\u002Fdeploy\u002F` for any `.xml` file whose root element is `\u003Clicense>` or `\u003Clicenses>`. If none is found, stop and ask the user to place their license file in `bundles\u002Fdeploy\u002F` before continuing. For Docker, apply the same check to the directory mounted to the container's deploy path. Community Edition and free tier products do not require a license — skip this check for those.\n- **License is consumed on boot**: Liferay registers the key into the database and deletes the file, so an empty `bundles\u002Fdeploy\u002F` on an already booted instance is the normal licensed state, not a missing license. Confirm activation from the log instead — `grep --extended-regexp --ignore-case 'license validation passed|License registered' bundles\u002Ftomcat*\u002Flogs\u002Fcatalina.out`. Because the license now lives in the database, **clearing `bundles\u002Fdata` also discards it**; copy a key again into `bundles\u002Fdeploy\u002F` as part of any such reset.\n\n### Environment Readiness and State Sync\n\n#### Configure MCP Before Starting the Server\n\nIf the Liferay MCP server is supported in your DXP version (see `skills\u002Fmcp-server\u002FSKILL.md`), set it up **now**, before starting Liferay. CLI agents load MCP settings at startup only, and the portal reads its feature flags at boot — getting either half wrong after the server is running costs another full server boot. Do it in this order:\n\n1. Load `skills\u002Fmcp-server\u002FSKILL.md` and run its \"Audit the Current State First\" table. Do not skip it because an MCP entry already appears in the agent's server list — that entry is only the client half and proves nothing about the portal's `LPD-63311` flag, which a fresh bundle never has.\n\n1. Complete only the steps the audit shows missing. Enable the flag in the configuration the bundle will boot with. Fix or add the client entry if needed.\n\n1. If the client configuration changed, prompt the user to exit and restart their CLI session, then verify the MCP server entry appears in the client's server list. A disconnected or failed status is expected — the server is not running yet. If the entry is absent, recheck the MCP configuration before proceeding.\n\n1. Then continue below to start the Liferay server.\n\nSkip this block if MCP is not supported in your DXP version.\n\n#### Tomcat\n\n- **Initialize**: run `blade server init` if `bundles\u002F` does not exist.\n\n- **Clear the seeded database (Hypersonic, before the first start)**: a downloaded bundle ships with a seeded Hypersonic database in which `test@liferay.com` already exists with the first login flags set. Boot it as is and every `\u002Fo\u002F*` call returns 403 no matter what `portal-ext.properties` contains, because those properties are read only when the admin is created.\n\n  Delete `bundles\u002Fdata` and `bundles\u002Fosgi\u002Fstate`.\n\n  Only for a bundle that has never been started — `bundles\u002Flogs` is empty and nothing answers on `http:\u002F\u002Flocalhost:${PORT}`. Otherwise skip this and use the manual login in First Login Bootstrap.\n\n- **BasicAuth verifier (dev only — required for headless REST and MCP)**: add to `configs\u002Flocal\u002Fportal-ext.properties` BEFORE first boot:\n\n  ```\n  auth.verifier.BasicAuthHeaderAuthVerifier.urls.includes=\u002Fapi\u002F*,\u002Fxmlrpc\u002F*,\u002Fo\u002F*\n  ```\n\n  Every headless REST endpoint hits `\u002Fo\u002F*`, and so does every MCP `call-http-endpoint` call on 2026.Q1 and 2026.Q2. Without this, those calls return 403. Adding it reactively costs an extra edit + sync + restart cycle.\n\n  **Security note**: this is for local development only. BasicAuth sends credentials in every request. For production, use OAuth2 with `OAuth2HeaderAuthVerifier` instead. Never enable BasicAuth on `\u002Fo\u002F*` in production.\n\n- **Instance and admin properties (dev only)**: a new workspace ships `configs\u002Flocal\u002Fportal-ext.properties` with nothing but commented-out JDBC lines, so add every line below rather than assuming any of them is already there:\n\n  ```\n  admin.email.from.address=test@liferay.com\n  admin.email.from.name=Test Test\n  company.default.time.zone=UTC\n  company.default.web.id=liferay.com\n  default.admin.email.address.prefix=test\n  passwords.default.policy.change.required=false\n  setup.wizard.enabled=false\n  terms.of.use.required=false\n  users.reminder.queries.enabled=false\n  ```\n\n  `setup.wizard.enabled=false`, `terms.of.use.required=false`, and `passwords.default.policy.change.required=false` remove the setup wizard, the Terms of Use screen, and the forced password change, and `users.reminder.queries.enabled=false` disables the password recovery security question prompt that otherwise follows that password change. `default.admin.email.address.prefix` and `company.default.web.id` combine into the admin login — `test` plus `liferay.com` is what makes the documented `test@liferay.com` \u002F `test` credentials work. `admin.email.from.address` and `admin.email.from.name` set the sender on portal notifications. `company.default.time.zone=UTC` keeps portal timestamps aligned with the UTC timestamps in `catalina.out`, which otherwise disagree with the local shell and make log correlation misleading.\n\n  Only some of these are read while the default company and its admin user are created: `admin.email.from.address`, `admin.email.from.name`, `company.default.time.zone`, `company.default.web.id`, `default.admin.email.address.prefix`, and `passwords.default.policy.change.required`. Those must be in place before the bundle has ever booted, because `PasswordPolicyLocalServiceImpl.checkDefaultPasswordPolicy` builds the default policy once and a later edit cannot rename an existing admin or clear a `passwordReset` flag already written to the database. `setup.wizard.enabled`, `terms.of.use.required`, and `users.reminder.queries.enabled` are read on each boot or login instead — `UserImpl` resolves the last two through `PrefsPropsUtil` every time — so adding them later still takes effect after a restart.\n\n- **Configuration sync — before the first start**: copy the local config into the bundle: `cp configs\u002Flocal\u002Fportal-ext.properties bundles\u002Fportal-ext.properties`. (This copy is destructive — see `skills\u002Fdeploy-and-verify\u002FSKILL.md` for the diff before sync rule.)\n\n  The properties above are what skip the manual first login, but they only take effect if this copy happens before the bundle has ever booted. See First Login Bootstrap below.\n\n- **Free port 8080 first**: every Liferay workspace defaults to 8080, so another workspace left running holds it. Run `ss -ltnp | grep ':8080 '` and **wait for the result before launching** — do not batch the check with the start command. If the port is taken, stop that instance with its own `bundles\u002Ftomcat*\u002Fbin\u002Fshutdown.sh` or move this workspace to another port. A bind conflict is easy to misread: Tomcat still logs `Server startup in [N] milliseconds` even though the connector never came up, so the boot looks fine while every request is served by the *other* instance and its separate database — which surfaces as inexplicable login or data failures. Treat `Address already in use` in `catalina.out` as a failed boot regardless of the startup line, and confirm the listening pid belongs to this bundle.\n\n- **Start server**: `blade server run` (foreground, recommended for debugging) or `blade server start` (background). These commands are Tomcat only — do not use them for Docker.\n\n- **Login**: use `test@liferay.com` \u002F `test` (or credentials found in `portal-ext.properties`).\n\n#### Docker\n\n- **Locate compose file**: search the workspace for `docker-compose.yaml` or `docker-compose.yml` — its location varies by project.\n- **Database**: verify the compose file defines a database service (MySQL). Docker has no embedded database; both the database and Liferay containers must be running.\n- **Configuration**: check whether the compose file uses `image:` (prebuilt) or `build:` (custom image):\n  - `image: liferay\u002Fdxp:...` (prebuilt) → configuration is in `liferay.env` (env vars). See `skills\u002Ffeature-flags\u002FSKILL.md` for the env var encoding.\n  - `build: ...` → configuration is baked into the image via `configs\u002Fdocker\u002F`. Rebuild the image to apply changes.\n- **Initial build**: before the first `docker compose up`, build and output client extensions to the volume mounted directory: `.\u002Fgradlew deploy`.\n- **Start**: `docker compose up` (foreground) or `docker compose up --detach` (background). Run from the directory containing the compose file.\n- **Login**: use credentials defined in `liferay.env` (default: `test@liferay.com` \u002F `test`).\n\n### Server Verification\n\n- **Tomcat**: watch `bundles\u002Ftomcat*\u002Flogs\u002Fcatalina.out` for `Server startup in [X] ms`. Then verify `http:\u002F\u002Flocalhost:${PORT}` is reachable.\n- **Docker**: poll the health check endpoint until it returns `200`: `curl --fail http:\u002F\u002Flocalhost:${PORT}\u002Fc\u002Fportal\u002Fstatus`. Then verify `http:\u002F\u002Flocalhost:${PORT}` is reachable. (Port may differ if the compose file maps a different host port.)\n\n### First Login Bootstrap (Mandatory Before API\u002FMCP Calls)\n\nOn a fresh Liferay instance, the default admin `test@liferay.com` is created with `passwordReset=true` and `agreedToTermsOfUse=false` in the database. Until the portal stops enforcing both, every authenticated API call (REST, or an MCP tool call) returns 403 — including for the Omni Admin user. `terms.of.use.required=false` and `users.reminder.queries.enabled=false` lift their half of that enforcement on any boot, but `passwordReset` is written when the admin is created, so only `passwords.default.policy.change.required=false` already in effect at that point avoids it.\n\n- **Cleared and synced before its first start**: nothing to do. The admin was created with the properties in effect, so `passwordReset` was never set.\n\n- **Already started**: the manual login is the only way through — syncing the properties now will not clear a `passwordReset` flag already in the database.\n\nPrompt the user to log into `http:\u002F\u002Flocalhost:${PORT}` as `test@liferay.com` \u002F `test`, accept the Terms of Use, and complete the password change (use `test` as the new password so existing credentials stay valid). Wait for their reply before making any API or MCP calls.\n\nDo not automate the browser login flow — Liferay's login form structure varies across versions and automation is brittle.\n\n### MCP Connection Check (When MCP Is Supported)\n\nWith the server running, first run the endpoint probe in `skills\u002Fmcp-server\u002FSKILL.md` → \"Audit the Current State First\". A `404` means `LPD-63311` is not in effect on the portal, whatever the agent's server list shows — enable it and restart Liferay before going further. On 2026.Q3, a `404` with the flag in effect means the `MCPServerConfiguration` switch is off; enable it per `skills\u002Fmcp-server\u002FSKILL.md`, which needs no restart. On 2026.Q1 and 2026.Q2, the probe does not check credentials; only a tool call does (see `skills\u002Fmcp-server\u002FSKILL.md` → \"Audit the Current State First\"). Then run the tool call in `skills\u002Fmcp-server\u002FSKILL.md` → \"Connection Check\". If it reports `Status code: 401` or `403`, or the probe returns HTTP `401` on 2026.Q3, stop and ask the user for updated credentials. If MCP tools are not visible, ensure the CLI session was restarted after configuration.\n\nOnly fall back to direct REST APIs if MCP has been configured correctly and is still returning errors. \"Not yet configured\" is not a valid fallback condition — configure it first.\n\n> **Feature flags**: before starting a task, check `skills\u002Ffeature-flags\u002FSKILL.md` for any flags required by the operation.\n\n## Guiding the User\n\nIf the user prompts for setup assistance, guide them through these steps one by one. Do not skip ahead. Explain what you are checking (e.g., \"I am verifying that your Liferay server is up\") and wait for processes to complete before writing code.\n\n## Success Signal\n\n- `gradle.properties` and `settings.gradle` present\n- `bundles\u002Ftomcat*\u002F` present\n- HTTP request to `http:\u002F\u002Flocalhost:${PORT}` returns 200\n- User can sign in with the default credentials\n- BasicAuth verifier configured (if doing local REST\u002FMCP work)\n- MCP endpoint probe returns 200 and the MCP server is connected in the agent (when MCP is supported)\n- First login bootstrap complete (or skipped via preboot flag settings)\n\n## References\n\n- Workspace docs: `https:\u002F\u002Flearn.liferay.com\u002Fw\u002Fdxp\u002Fdevelopment\u002Ftooling\u002Fliferay-workspace`\n- Creating a workspace: `https:\u002F\u002Flearn.liferay.com\u002Fw\u002Fdxp\u002Fdevelopment\u002Ftooling\u002Fliferay-workspace\u002Fcreating-a-liferay-workspace`\n- Blade CLI: `https:\u002F\u002Flearn.liferay.com\u002Fw\u002Fdxp\u002Fdevelopment\u002Ftooling\u002Fblade-cli`\n- Course: `https:\u002F\u002Flearn.liferay.com\u002Fcourse\u002Fmastering-liferay-workspaces-and-tooling\u002Fw-t-introduction\u002Fw-t-introduction`","# Workspace Init\n\nStand up a working Liferay Workspace from zero, or diagnose a workspace that looks uninitialized. Covers `blade init`, bundle download, license setup, BasicAuth verifier, server start, and first login bootstrap.\n\n## When to Invoke\n\n- The user asks to set up, initialize, or scaffold a workspace, or asks for setup help.\n- The server appears down or unreachable.\n- The workspace looks uninitialized — missing `bundles\u002F`, or missing `gradle.properties`.\n- Do not run through all steps for a returning user whose server is already running.\n\n> **Note:** These rules apply to local workspace initialization and must not be used to configure higher environments (UAT\u002FProd).\n\n## Workflow\n\n### Version and Tooling Check\n\n- **Check version**: read `liferay.workspace.product` in `gradle.properties`.\n- **Verify tooling**: check that `blade` (`blade --version`) and Java (`javac -version`) are installed. If missing, provide installation steps.\n- **DXP License**: if `liferay.workspace.product` contains `dxp`, a license file is required. Liferay identifies license files by XML content, not filename — check `bundles\u002Fdeploy\u002F` for any `.xml` file whose root element is `\u003Clicense>` or `\u003Clicenses>`. If none is found, stop and ask the user to place their license file in `bundles\u002Fdeploy\u002F` before continuing. For Docker, apply the same check to the directory mounted to the container's deploy path. Community Edition and free tier products do not require a license — skip this check for those.\n- **License is consumed on boot**: Liferay registers the key into the database and deletes the file, so an empty `bundles\u002Fdeploy\u002F` on an already booted instance is the normal licensed state, not a missing license. Confirm activation from the log instead — `grep --extended-regexp --ignore-case 'license validation passed|License registered' bundles\u002Ftomcat*\u002Flogs\u002Fcatalina.out`. Because the license now lives in the database, **clearing `bundles\u002Fdata` also discards it**; copy a key again into `bundles\u002Fdeploy\u002F` as part of any such reset.\n\n### Environment Readiness and State Sync\n\n#### Configure MCP Before Starting the Server\n\nIf the Liferay MCP server is supported in your DXP version (see `skills\u002Fmcp-server\u002FSKILL.md`), set it up **now**, before starting Liferay. CLI agents load MCP settings at startup only, and the portal reads its feature flags at boot — getting either half wrong after the server is running costs another full server boot. Do it in this order:\n\n1. Load `skills\u002Fmcp-server\u002FSKILL.md` and run its \"Audit the Current State First\" table. Do not skip it because an MCP entry already appears in the agent's server list — that entry is only the client half and proves nothing about the portal's `LPD-63311` flag, which a fresh bundle never has.\n\n1. Complete only the steps the audit shows missing. Enable the flag in the configuration the bundle will boot with. Fix or add the client entry if needed.\n\n1. If the client configuration changed, prompt the user to exit and restart their CLI session, then verify the MCP server entry appears in the client's server list. A disconnected or failed status is expected — the server is not running yet. If the entry is absent, recheck the MCP configuration before proceeding.\n\n1. Then continue below to start the Liferay server.\n\nSkip this block if MCP is not supported in your DXP version.\n\n#### Tomcat\n\n- **Initialize**: run `blade server init` if `bundles\u002F` does not exist.\n\n- **Clear the seeded database (Hypersonic, before the first start)**: a downloaded bundle ships with a seeded Hypersonic database in which `test@liferay.com` already exists with the first login flags set. Boot it as is and every `\u002Fo\u002F*` call returns 403 no matter what `portal-ext.properties` contains, because those properties are read only when the admin is created.\n\n  Delete `bundles\u002Fdata` and `bundles\u002Fosgi\u002Fstate`.\n\n  Only for a bundle that has never been started — `bundles\u002Flogs` is empty and nothing answers on `http:\u002F\u002Flocalhost:${PORT}`. Otherwise skip this and use the manual login in First Login Bootstrap.\n\n- **BasicAuth verifier (dev only — required for headless REST and MCP)**: add to `configs\u002Flocal\u002Fportal-ext.properties` BEFORE first boot:\n\n  ```\n  auth.verifier.BasicAuthHeaderAuthVerifier.urls.includes=\u002Fapi\u002F*,\u002Fxmlrpc\u002F*,\u002Fo\u002F*\n  ```\n\n  Every headless REST endpoint hits `\u002Fo\u002F*`, and so does every MCP `call-http-endpoint` call on 2026.Q1 and 2026.Q2. Without this, those calls return 403. Adding it reactively costs an extra edit + sync + restart cycle.\n\n  **Security note**: this is for local development only. BasicAuth sends credentials in every request. For production, use OAuth2 with `OAuth2HeaderAuthVerifier` instead. Never enable BasicAuth on `\u002Fo\u002F*` in production.\n\n- **Instance and admin properties (dev only)**: a new workspace ships `configs\u002Flocal\u002Fportal-ext.properties` with nothing but commented-out JDBC lines, so add every line below rather than assuming any of them is already there:\n\n  ```\n  admin.email.from.address=test@liferay.com\n  admin.email.from.name=Test Test\n  company.default.time.zone=UTC\n  company.default.web.id=liferay.com\n  default.admin.email.address.prefix=test\n  passwords.default.policy.change.required=false\n  setup.wizard.enabled=false\n  terms.of.use.required=false\n  users.reminder.queries.enabled=false\n  ```\n\n  `setup.wizard.enabled=false`, `terms.of.use.required=false`, and `passwords.default.policy.change.required=false` remove the setup wizard, the Terms of Use screen, and the forced password change, and `users.reminder.queries.enabled=false` disables the password recovery security question prompt that otherwise follows that password change. `default.admin.email.address.prefix` and `company.default.web.id` combine into the admin login — `test` plus `liferay.com` is what makes the documented `test@liferay.com` \u002F `test` credentials work. `admin.email.from.address` and `admin.email.from.name` set the sender on portal notifications. `company.default.time.zone=UTC` keeps portal timestamps aligned with the UTC timestamps in `catalina.out`, which otherwise disagree with the local shell and make log correlation misleading.\n\n  Only some of these are read while the default company and its admin user are created: `admin.email.from.address`, `admin.email.from.name`, `company.default.time.zone`, `company.default.web.id`, `default.admin.email.address.prefix`, and `passwords.default.policy.change.required`. Those must be in place before the bundle has ever booted, because `PasswordPolicyLocalServiceImpl.checkDefaultPasswordPolicy` builds the default policy once and a later edit cannot rename an existing admin or clear a `passwordReset` flag already written to the database. `setup.wizard.enabled`, `terms.of.use.required`, and `users.reminder.queries.enabled` are read on each boot or login instead — `UserImpl` resolves the last two through `PrefsPropsUtil` every time — so adding them later still takes effect after a restart.\n\n- **Configuration sync — before the first start**: copy the local config into the bundle: `cp configs\u002Flocal\u002Fportal-ext.properties bundles\u002Fportal-ext.properties`. (This copy is destructive — see `skills\u002Fdeploy-and-verify\u002FSKILL.md` for the diff before sync rule.)\n\n  The properties above are what skip the manual first login, but they only take effect if this copy happens before the bundle has ever booted. See First Login Bootstrap below.\n\n- **Free port 8080 first**: every Liferay workspace defaults to 8080, so another workspace left running holds it. Run `ss -ltnp | grep ':8080 '` and **wait for the result before launching** — do not batch the check with the start command. If the port is taken, stop that instance with its own `bundles\u002Ftomcat*\u002Fbin\u002Fshutdown.sh` or move this workspace to another port. A bind conflict is easy to misread: Tomcat still logs `Server startup in [N] milliseconds` even though the connector never came up, so the boot looks fine while every request is served by the *other* instance and its separate database — which surfaces as inexplicable login or data failures. Treat `Address already in use` in `catalina.out` as a failed boot regardless of the startup line, and confirm the listening pid belongs to this bundle.\n\n- **Start server**: `blade server run` (foreground, recommended for debugging) or `blade server start` (background). These commands are Tomcat only — do not use them for Docker.\n\n- **Login**: use `test@liferay.com` \u002F `test` (or credentials found in `portal-ext.properties`).\n\n#### Docker\n\n- **Locate compose file**: search the workspace for `docker-compose.yaml` or `docker-compose.yml` — its location varies by project.\n- **Database**: verify the compose file defines a database service (MySQL). Docker has no embedded database; both the database and Liferay containers must be running.\n- **Configuration**: check whether the compose file uses `image:` (prebuilt) or `build:` (custom image):\n  - `image: liferay\u002Fdxp:...` (prebuilt) → configuration is in `liferay.env` (env vars). See `skills\u002Ffeature-flags\u002FSKILL.md` for the env var encoding.\n  - `build: ...` → configuration is baked into the image via `configs\u002Fdocker\u002F`. Rebuild the image to apply changes.\n- **Initial build**: before the first `docker compose up`, build and output client extensions to the volume mounted directory: `.\u002Fgradlew deploy`.\n- **Start**: `docker compose up` (foreground) or `docker compose up --detach` (background). Run from the directory containing the compose file.\n- **Login**: use credentials defined in `liferay.env` (default: `test@liferay.com` \u002F `test`).\n\n### Server Verification\n\n- **Tomcat**: watch `bundles\u002Ftomcat*\u002Flogs\u002Fcatalina.out` for `Server startup in [X] ms`. Then verify `http:\u002F\u002Flocalhost:${PORT}` is reachable.\n- **Docker**: poll the health check endpoint until it returns `200`: `curl --fail http:\u002F\u002Flocalhost:${PORT}\u002Fc\u002Fportal\u002Fstatus`. Then verify `http:\u002F\u002Flocalhost:${PORT}` is reachable. (Port may differ if the compose file maps a different host port.)\n\n### First Login Bootstrap (Mandatory Before API\u002FMCP Calls)\n\nOn a fresh Liferay instance, the default admin `test@liferay.com` is created with `passwordReset=true` and `agreedToTermsOfUse=false` in the database. Until the portal stops enforcing both, every authenticated API call (REST, or an MCP tool call) returns 403 — including for the Omni Admin user. `terms.of.use.required=false` and `users.reminder.queries.enabled=false` lift their half of that enforcement on any boot, but `passwordReset` is written when the admin is created, so only `passwords.default.policy.change.required=false` already in effect at that point avoids it.\n\n- **Cleared and synced before its first start**: nothing to do. The admin was created with the properties in effect, so `passwordReset` was never set.\n\n- **Already started**: the manual login is the only way through — syncing the properties now will not clear a `passwordReset` flag already in the database.\n\nPrompt the user to log into `http:\u002F\u002Flocalhost:${PORT}` as `test@liferay.com` \u002F `test`, accept the Terms of Use, and complete the password change (use `test` as the new password so existing credentials stay valid). Wait for their reply before making any API or MCP calls.\n\nDo not automate the browser login flow — Liferay's login form structure varies across versions and automation is brittle.\n\n### MCP Connection Check (When MCP Is Supported)\n\nWith the server running, first run the endpoint probe in `skills\u002Fmcp-server\u002FSKILL.md` → \"Audit the Current State First\". A `404` means `LPD-63311` is not in effect on the portal, whatever the agent's server list shows — enable it and restart Liferay before going further. On 2026.Q3, a `404` with the flag in effect means the `MCPServerConfiguration` switch is off; enable it per `skills\u002Fmcp-server\u002FSKILL.md`, which needs no restart. On 2026.Q1 and 2026.Q2, the probe does not check credentials; only a tool call does (see `skills\u002Fmcp-server\u002FSKILL.md` → \"Audit the Current State First\"). Then run the tool call in `skills\u002Fmcp-server\u002FSKILL.md` → \"Connection Check\". If it reports `Status code: 401` or `403`, or the probe returns HTTP `401` on 2026.Q3, stop and ask the user for updated credentials. If MCP tools are not visible, ensure the CLI session was restarted after configuration.\n\nOnly fall back to direct REST APIs if MCP has been configured correctly and is still returning errors. \"Not yet configured\" is not a valid fallback condition — configure it first.\n\n> **Feature flags**: before starting a task, check `skills\u002Ffeature-flags\u002FSKILL.md` for any flags required by the operation.\n\n## Guiding the User\n\nIf the user prompts for setup assistance, guide them through these steps one by one. Do not skip ahead. Explain what you are checking (e.g., \"I am verifying that your Liferay server is up\") and wait for processes to complete before writing code.\n\n## Success Signal\n\n- `gradle.properties` and `settings.gradle` present\n- `bundles\u002Ftomcat*\u002F` present\n- HTTP request to `http:\u002F\u002Flocalhost:${PORT}` returns 200\n- User can sign in with the default credentials\n- BasicAuth verifier configured (if doing local REST\u002FMCP work)\n- MCP endpoint probe returns 200 and the MCP server is connected in the agent (when MCP is supported)\n- First login bootstrap complete (or skipped via preboot flag settings)\n\n## References\n\n- Workspace docs: `https:\u002F\u002Flearn.liferay.com\u002Fw\u002Fdxp\u002Fdevelopment\u002Ftooling\u002Fliferay-workspace`\n- Creating a workspace: `https:\u002F\u002Flearn.liferay.com\u002Fw\u002Fdxp\u002Fdevelopment\u002Ftooling\u002Fliferay-workspace\u002Fcreating-a-liferay-workspace`\n- Blade CLI: `https:\u002F\u002Flearn.liferay.com\u002Fw\u002Fdxp\u002Fdevelopment\u002Ftooling\u002Fblade-cli`\n- Course: `https:\u002F\u002Flearn.liferay.com\u002Fcourse\u002Fmastering-liferay-workspaces-and-tooling\u002Fw-t-introduction\u002Fw-t-introduction`",{"name":47,"description":48},"workspace-init","Bootstrap a Liferay Workspace, download and verify the bundle, set up auth verifiers, and complete first login bootstrap. Use when the user is starting fresh, when the server appears down or unreachable, when gradle.properties or bundles\u002F is missing, or when the user asks to set up, initialize, or scaffold a workspace.","master","02992542dbd5a9d65782cdc1d0c3151ddc3debb3","plugins\u002F10x-swe\u002Fskills\u002Fjujutsu-vcs",0,"https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe","https:\u002F\u002Fgithub.com\u002Fcercova-studios","2026-11-08 11:59:58",{"source":8,"skillName":47,"commands":57,"prompt":67,"zipAvailable":68},[58,61,64],{"tool":59,"command":60},"npx","npx skills add cercova-studios\u002F10x-swe --skill workspace-init",{"tool":62,"command":63},"bunx","bunx skills add cercova-studios\u002F10x-swe --skill workspace-init",{"tool":65,"command":66},"pnpm","pnpm dlx skills add cercova-studios\u002F10x-swe --skill workspace-init","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fjujutsu-vcs\u002FSKILL.md",true,[70,76,80,84,88,92,96,100,104,108,112,116,120],{"path":71,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":74,"sourceHtmlUrl":75},"references\u002Fbookmarks.md","REFERENCE","参考文档",5883,"https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fjujutsu-vcs\u002Freferences\u002Fbookmarks.md",{"path":77,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":78,"sourceHtmlUrl":79},"references\u002Fcoding-agents.md",7587,"https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fjujutsu-vcs\u002Freferences\u002Fcoding-agents.md",{"path":81,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":82,"sourceHtmlUrl":83},"references\u002Fcommon-patterns.md",6871,"https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fjujutsu-vcs\u002Freferences\u002Fcommon-patterns.md",{"path":85,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":86,"sourceHtmlUrl":87},"references\u002Fcore-concepts.md",6095,"https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fjujutsu-vcs\u002Freferences\u002Fcore-concepts.md",{"path":89,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":90,"sourceHtmlUrl":91},"references\u002Fgit-command-mapping.md",6357,"https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fjujutsu-vcs\u002Freferences\u002Fgit-command-mapping.md",{"path":93,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":94,"sourceHtmlUrl":95},"references\u002Frevsets.md",6102,"https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fjujutsu-vcs\u002Freferences\u002Frevsets.md",{"path":97,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":98,"sourceHtmlUrl":99},"references\u002Ftroubleshooting.md",7222,"https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fjujutsu-vcs\u002Freferences\u002Ftroubleshooting.md",{"path":101,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":102,"sourceHtmlUrl":103},"workflows\u002Fcollaborate-github.md",4496,"https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fjujutsu-vcs\u002Fworkflows\u002Fcollaborate-github.md",{"path":105,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":106,"sourceHtmlUrl":107},"workflows\u002Fgetting-started.md",2829,"https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fjujutsu-vcs\u002Fworkflows\u002Fgetting-started.md",{"path":109,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":110,"sourceHtmlUrl":111},"workflows\u002Fmake-changes.md",3363,"https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fjujutsu-vcs\u002Fworkflows\u002Fmake-changes.md",{"path":113,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":114,"sourceHtmlUrl":115},"workflows\u002Frecover-mistakes.md",4315,"https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fjujutsu-vcs\u002Fworkflows\u002Frecover-mistakes.md",{"path":117,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":118,"sourceHtmlUrl":119},"workflows\u002Fresolve-conflicts.md",4019,"https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fjujutsu-vcs\u002Fworkflows\u002Fresolve-conflicts.md",{"path":121,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":122,"sourceHtmlUrl":123},"workflows\u002Fwork-with-history.md",3835,"https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fjujutsu-vcs\u002Fworkflows\u002Fwork-with-history.md",[125,165,200,219,238,250],{"skillNo":126,"name":127,"nameZh":6,"description":128,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":129,"licenseFileUrl":130,"sourceHtmlUrl":131,"categories":132,"keywords":138,"publishedAt":42},"01M6CD3T6EQ9N5KPNXCM6ABHVA","turnstile-spin","Set up Cloudflare Turnstile end-to-end in a project. Scan the codebase, create the widget via the Cloudflare API, embed it where user requests need bot verification (form submissions, SPA actions, API endpoints, download links, comment or vote submissions, etc.), wire canonical server-side siteverify in the customer's existing backend, validate, and persist the skill. Load this when a user asks to add Turnstile, set up CAPTCHA, protect a form or endpoint from bots, or fix a Turnstile integration. Uses Cloudflare's documented Turnstile contract.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fturnstile-spin\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fturnstile-spin\u002FSKILL.md",[133],{"categoryNo":134,"categoryName":135,"taxonomyType":136,"taxonomyTypeDesc":137},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",[139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,23],"turnstile spin","bot","customer","plugin","create","permissions","verification","cloudflare","integration","server","actions","nextjs","SET","api","astro","sveltekit","fix","backend","up","endpoints","bots","project","spa","end","app","SWE",{"skillNo":166,"name":167,"nameZh":6,"description":168,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":129,"licenseFileUrl":169,"sourceHtmlUrl":170,"categories":171,"keywords":183,"publishedAt":42},"01M6CD0BJYRNV610HYYPX933RE","frontend-design","Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Ffrontend-design\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Ffrontend-design\u002FSKILL.md",[172,175,178],{"categoryNo":173,"categoryName":174,"taxonomyType":136,"taxonomyTypeDesc":137},"01JBSEEDCAT000000000000009","前端开发",{"categoryNo":176,"categoryName":177,"taxonomyType":136,"taxonomyTypeDesc":137},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":179,"categoryName":180,"taxonomyType":181,"taxonomyTypeDesc":182},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",[184,185,186,187,188,189,143,190,191,192,193,35,33,194,195,196,197,26,198,199,23],"frontend","design","frontend design","web","components","web components","code","Production","applications","quality","creative","build","pages","aesthetics","high","generic",{"skillNo":201,"name":202,"nameZh":6,"description":203,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":204,"categories":205,"keywords":206,"publishedAt":42},"01M6CD4QX8C4DST98AY21HEYCM","source-insights","Prepare inspected source evidence, preserve exact citations, and publish reviewed insights into an explicit local library.","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002Fknowledge\u002Fskills\u002Fsource-insights\u002FSKILL.md",[],[207,208,209,40,210,211,212,213,214,215,216,217,218],"source insights","insights","source","prepare","library","publish","Citations","global","session","evidence","local","preserve",{"skillNo":220,"name":221,"nameZh":6,"description":222,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":223,"categories":224,"keywords":228,"publishedAt":42},"01M6CD4N1HVNC1EXPEBZT7YS31","skill-graph","Discover skills and workflows through independent lexical search, relationship paths and a terminal graph.","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002Fknowledge\u002Fskills\u002Fskill-graph\u002FSKILL.md",[225],{"categoryNo":226,"categoryName":227,"taxonomyType":136,"taxonomyTypeDesc":137},"01JBSEEDCAT000000000000023","Skill与智能体开发",[229,230,231,40,142,232,233,214,234,235,236,237,164],"graph","skill graph","terminal","search","10x","relationship","discover","paths","discover skills",{"skillNo":239,"name":240,"nameZh":6,"description":241,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":242,"categories":243,"keywords":244,"publishedAt":42},"01M6CD4HQKXNZ57YEGD8QVK6Z6","session-search","Recall public session turns with exact provenance, bounded excerpts and independent piped exports.","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002Fknowledge\u002Fskills\u002Fsession-search\u002FSKILL.md",[],[232,215,245,40,246,247,248,214,26,208,209,249],"session search","provenance","recall","public","bounded",{"skillNo":251,"name":252,"nameZh":6,"description":253,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":254,"categories":255,"keywords":262,"publishedAt":42},"01M6CD4ET7DVNBYPDAMAYMSK2T","newsletter","Produce a private local AI newsletter from bounded public research, with cited deep dives, HTML\u002FMarkdown output, Dagu scheduling and seven-day retention.","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002Fknowledge\u002Fskills\u002Fnewsletter\u002FSKILL.md",[256,259],{"categoryNo":257,"categoryName":258,"taxonomyType":136,"taxonomyTypeDesc":137},"01JBSEEDCAT000000000000005","邮件与沟通",{"categoryNo":260,"categoryName":261,"taxonomyType":136,"taxonomyTypeDesc":137},"01JBSEEDCAT000000000000021","资料检索与研究",[252,263,40,264,265,248,214,266,21,267,268,269,217,270,271,272,26,249],"research","produce","markdown","html","scheduling","local ai","dagu","deep","retention","output"]