Run DocsGPT without Docker: the API and the worker each become a service
on the machine itself, a launchd agent on macOS and a systemd user unit
on Linux, pointed at a PostgreSQL and a Redis that already run.
`docsgpt up --native --postgres-uri ... --redis-url ...` writes the same
.env a Docker install uses, applies the migrations and starts both
services. status, logs, down and uninstall work on a native install the
same way they do on a Docker one, and never touch the database or Redis:
they were the user's to begin with.
One Redis URL covers the broker, the result backend and the cache on
three consecutive databases, starting at the one the URL names, so a
Redis that already holds something else can be shared.
Windows has neither service manager, so native mode refuses it and says
what to do instead.
- install.sh saves the get.docker.com and uv installers to a file and runs
them only after the download finished, so a cut-off transfer runs nothing.
- Neither installer prints DOCSGPT_PACKAGE, which may be a URL with
credentials.
- The CI step assigns the wheel path before exporting it, so a missing wheel
fails instead of installing from PyPI.
- Docker-Deploying shows one code block per platform; Quickstart names the
/opt/docsgpt home used for root on Linux.
deployment/install.sh (curl | bash) and install.ps1 (irm | iex) check for
Docker, install uv when it is missing or older than 0.8 (pinned 0.12.15 via
Astral's installer), install or upgrade the docsgpt package with
`uv tool install`, and hand the terminal to `docsgpt up` with any arguments.
On Linux without Docker the shell installer offers get.docker.com. Both run
entirely inside a function, so a download cut short runs nothing.
Releases attach both scripts next to the Compose file, which is where
docs.ac/install and docs.ac/install.ps1 will point. installer-lint.yml runs
shellcheck and the PowerShell parser; docker-image-verify.yml now installs
through install.sh. README, Quickstart, Docker-Deploying and the changelog
lead with the one-liner.
envfile.update only applied 0600 when it created the file, so an existing
.env with a wider mode kept it while secrets were written into it. The mode
is now set on the open descriptor before the file is truncated and written.
The CI step now requires POSTGRES_PASSWORD and JWT_SECRET_KEY to have values:
an empty one falls back to a default without any check noticing.
Docker-Deploying gains a `docsgpt up` section, Pip-Install and Upgrading
describe the ~/.docsgpt/server data home, and the changelog covers both.
docker-image-verify.yml installs the wheel and runs `docsgpt up`, `status`,
a second `up` that must keep the secrets, and `uninstall --purge` against
the image it built. The standalone Compose file maps host.docker.internal
to the host gateway, so a model server on a Linux host is reachable the way
`docsgpt up` suggests.
`docsgpt up` copies the standalone Compose file shipped with this package
version into the stack directory (~/.docsgpt/server by default), writes its
.env and starts the stack on the images of the same version. A first run
asks who should reach DocsGPT (this computer, the network with a token, or a
domain with HTTPS) and which model provider to use; flags answer the same
questions for scripts. Re-running keeps secrets and settings and moves the
image tag, and the database password is only generated for a new database.
Also: down, status, logs, token, open, env, upgrade (uv tool installs
upgrade themselves and run `up` again) and uninstall (keeps settings and
data unless --purge). The commands import no Flask, Celery or settings.
The wheel carries deployment/docker-compose-standalone.yaml as
docsgpt/deploy/docker-compose.yaml; the sdist includes the source file.
The backend image builds the web UI with scripts/build_frontend.sh and
serves it through docsgpt/ui.py, so the standalone Compose file drops the
frontend container. UI and API share port 7091, published on 127.0.0.1
unless DOCSGPT_BIND says otherwise. POSTGRES_PASSWORD is configurable, and
an optional https profile puts Caddy in front of a public domain.
docker-image-verify.yml starts the standalone stack on the image it built
and checks the API, the UI, /config.js and a client-side route on one port.
The version input reached checkout as a bare ref, so a manual run given a
branch name would have built that branch and published it as an image tag,
`latest` included. It also meant a version that happens to match a branch name
would silently resolve to the branch rather than the tag.
Resolve it under refs/tags/ instead. Plain versions from backend-release keep
working, and anything that is not a tag fails at checkout.
A manual run takes the version as an input but the checkout had no ref, so it
built whatever the run was dispatched from. Dispatching off main to rebuild an
older release would have published current main under that release's tags, and
moved `latest` to it.
Check out the version instead, falling back to the run's own ref when there is
no version, which is the push that publishes `develop`. The release and call
paths already checked out the right commit; this makes them explicit and fails
loudly on a version with no tag rather than mislabelling an image. The compose
file attached to the release now comes from the tag too.
None of the three image workflows could be started manually, so when 0.20.0
tagged before the release chain knew about the frontend and sandbox images,
there was no way to build those images for the tag short of recreating the
release. Add a workflow_dispatch trigger taking the version to build.
A manual run also gets a `move_latest` switch, so rebuilding an older tag does
not drag `latest` backwards. The rule for the moving tag now lives in the
manifest step's shell rather than in a nested expression: `latest` follows the
build unless the release is a prerelease, the run asked it not to, or it is the
rolling `develop` build.
0.20.0 failed to upload with "Certificate's Build Config URI ... does not
match expected Trusted Publisher". Authentication was fine: trusted publishing
matches the called workflow, pypi-publish.yml, which is what PyPI is
configured with. The PEP 740 attestation the publish action attaches by
default records the workflow that STARTED the run instead, backend-release.yml,
and PyPI verifies that against the same publisher entry. The two claims can
never agree while the publish runs as a called workflow, and no publisher
configuration satisfies both.
Attest only when this file is the entry point, which covers the manual
dispatch and a release published by hand. The release chain uploads unattested
rather than failing.
The earlier rehearsal went to TestPyPI and passed, so this only appeared on the
real index.
`release: published` fires for prereleases too, and every manifest job pushed
`latest` unconditionally, so publishing a release candidate by hand would have
made it the image everyone pulls. The backend image had the same hole, so fix
all three rather than only the two added here.
A release the backend-release workflow calls is always stable, so the
workflow_call path keeps moving `latest`; the release-event path moves it only
when the release is not a prerelease.
deployment/k8s/deployments/sandbox-deploy.yaml pulls arc53/docsgpt-sandbox,
which has never been pushed anywhere: Compose builds the runner from the
checkout (`build: ./sandbox`), but Kubernetes cannot build, so enabling code
execution on a cluster failed on an image that does not exist.
Build and push it like the other two images: `develop` on a push to main that
touches deployment/sandbox, and `<version>` plus `latest` when the release
workflow calls it. Release and develop live in one file here rather than two,
because the runner changes rarely and the only difference is which tags move.
The tag comes from the inputs and the release payload, not from
`github.event_name`, which is `push` when backend-release calls this.
backend-release.yml creates the GitHub release with GITHUB_TOKEN, and GitHub
never starts workflows from events that token produces, so the frontend image
workflow's `release: published` trigger does not fire for a version bump on
main. It was the only publish workflow left out of the workflow_call fix, so
the next bump would push arc53/docsgpt:<version> and move docsgpt:latest while
docsgpt-fe stayed on the previous release — and the standalone compose file
defaults both images to latest.
Give cife.yml a workflow_call trigger with a version input (same shape as
ci.yml) and call it from backend-release.yml after the release is created. The
release trigger stays for releases created by hand.
While here, bring it in line with ci.yml: run the publishing jobs in the
docker-hub environment, tag from the public arc53 namespace instead of the
login secret, pin the actions by digest, add the OCI version label, and drop
the QEMU step that only ran on the native arm64 runner.
`uv lock --upgrade` plus the two code changes the new versions need.
firecrawl-anydoc 0.2.4 raises a dedicated `NeedsOcrError` where 0.2.3 raised
`UnsupportedError("... OCR is required")`, so the anydoc parser no longer
recognised a scanned PDF: the fallback still ran, but a near-empty result was
stored as an empty document instead of failing with the OCR_ENABLED hint.
`_needs_ocr` now accepts both spellings and looks the class up lazily, so an
older anydoc keeps working. 0.2.4 also refuses the CID-font NDA fixture
outright rather than dropping its Chinese column silently, so the PDF
trust-check tests stub that dropped output against the fixture's real bytes
(the check's own inputs) and a new test pins the refusal path.
ruff 0.16 widened its implicit default rule set, turning the dev-group bump
into 7131 findings across the tree. `.ruff.toml` now states the historical
selection (E4, E7, E9, F) explicitly and the CI pin moves to the locked
0.16.7, so lint no longer drifts with the version.
pip install docsgpt now brings the web UI with it: `docsgpt api` serves the
API and the UI on one port.
- scripts/build_frontend.sh builds the frontend into docsgpt/static
(gitignored) the way the frontend image does: .env.development as the
production baseline, and index.html loading /config.js ahead of the
bundle. hatch admits the directory into the wheel and the sdist through
`artifacts`; the package workflows run the script before `uv build` and
fail if the wheel lacks the UI. The backend image keeps ignoring it.
- docsgpt/ui.py serves the build in front of Flask: files as they are,
hashed assets immutable, Flask's own path prefixes (taken from its URL map,
so new blueprints need no registration) passed through, every other GET
rendered as index.html for the client-side router. /config.js is generated
per request with VITE_API_HOST and VITE_BASE_URL set to the page's origin,
VITE_* environment variables winning. SERVE_UI=false leaves the API alone.
- docsgpt api configures gunicorn in code (gunicorn.app.base.Application)
instead of rewriting sys.argv, so the SIGUSR2 re-exec that gunicorn uses
for zero-downtime upgrades runs the docsgpt console script again and
works; verified with a live handover.
- Docs: the pip page says the UI is included, that DOCSGPT_HOME and
DOCSGPT_ENV_FILE are process environment variables rather than .env
entries, and the settings page describes SERVE_UI.
A caller passing a target other than pypi or testpypi would skip both
publish jobs and upload nothing; the build job now fails with the value
instead. Empty (the release event) stays valid.
Run 34260211236 on the pull request called pypi-publish.yml through
workflow_call aimed at TestPyPI: the trusted-publishing exchange succeeded,
attestations were generated, and both archives were uploaded (already
present, so skipped). Same-repository reusable workflows pass PyPI's
job_workflow_ref check, which names the called file.
- backend-release checks the tag and the release separately and publishes
only when it created the release in this run. A run that pushed the tag and
then failed to create the release used to skip both on re-run.
- pypi-publish accepts a `target` from callers (default pypi) so the
reusable-workflow path can be rehearsed against TestPyPI; the TestPyPI job
skips files that already exist there.
- A temporary workflow, to be removed before merge, calls pypi-publish the
way backend-release does, aimed at TestPyPI, on this pull request: PyPI
verifies the job_workflow_ref claim, which names the called file, so the
run proves the trusted-publishing path through workflow_call.
- zizmor-action v0.6.3: the pinned v0.5.2 bundles zizmor 1.23, which cannot
parse the `uses: $/...` self-repository syntax and aborted the audit.
backend-release creates the GitHub release with GITHUB_TOKEN, and GitHub
never starts workflows from events that token produces, so the
`release: published` triggers on the Docker and PyPI publish workflows only
fired for releases made by hand. 0.18.0 got no Docker images for that
reason, and 0.19.0 reached PyPI by a manual run.
backend-release now calls both publish workflows after creating the release,
passing the version it tagged. Both workflows gain a `workflow_call` trigger
with a `version` input and read the tag from it or from the release event,
so a release created by hand still publishes through the release trigger.
The Docker Hub credentials are passed by name; the PyPI job authenticates
through trusted publishing, which matches the called workflow's filename and
environment, so the publisher configuration is unchanged.
Permissions in backend-release move from the workflow to the jobs: the
release job writes contents; the Docker call writes contents (the compose
file attached to the release) and packages; the PyPI call gets an OIDC token.
pip install docsgpt (extras: docling, milvus) installs the backend with a
docsgpt command: api, worker, migrate, prefetch-models, verify-offline,
reembed. Second step of the PyPI work after the package rename.
- hatchling build; the version comes from docsgpt/version.py. The wheel is
the docsgpt package with the data it reads at runtime (prompts, model
catalogs, seed config, alembic.ini and migrations) and without the
Dockerfile, the exported requirements, the sample index and local runtime
data. The application import alias stays checkout-only. uv sync installs
the package editable now that [tool.uv] package = false is gone.
- docsgpt/cli.py: api (gunicorn + BoundedDrainUvicornWorker with the image's
flags, --reload for uvicorn), worker (Celery worker with beat embedded,
--no-beat/-Q/--concurrency/--pool, solo pool on macOS), migrate, and
argument pass-through to the maintenance scripts. --help imports no app.
- docsgpt/core/paths.py: runtime data lives in a data home (DOCSGPT_HOME,
else the checkout, else cwd); DOCSGPT_ENV_FILE overrides the env file.
Settings, the dotenv load, LocalStorage and the internal upload route use
it instead of "three directories above this file", which is site-packages
for an installed package. A checkout and the Docker image behave as before.
- [project] dependencies are compatible ranges so the package installs next
to other packages; uv.lock resolves to the same versions and the exported
requirements files are unchanged.
- package-build.yml builds and checks the wheel on PRs and installs it into
a clean venv; pypi-publish.yml publishes on a published release through
trusted publishing (environment pypi), or to TestPyPI on a manual run.
- Docs: Deploying -> Install with pip. AGENTS.md notes the package.
- The post-task reclaim skip recognises the legacy application.* embed name,
so query embeds queued by the previous release do not pay a full collect.
- The Azure compose file mounts host data on /app/{indexes,inputs,vectors},
where the process actually reads and writes; it mounted /app/application/...
before the rename and /app/docsgpt/... after it, and nothing wrote to either.
- The offline image check triggers on docsgpt/requirements*.txt again;
dependabot's pip entry points at docsgpt/.
- install_hint() and its docstring name docsgpt/requirements-<extra>.txt;
the test asserts the full path.
- application/vectors/ stays ignored: the compose files still mount it.
- The durability QA script quiets the docsgpt logger tree.
- Upgrade note: the three renamed source-sync entries start their timers
from the upgrade.
- CI installs the backend requirements from docsgpt/; the old cd into
application/ silently installed nothing.
- The root .dockerignore re-admits only application/__init__.py. An upgraded
checkout may still hold gitignored application/{inputs,indexes,vectors,.env}
from the old layout, and the directory rule shipped them into the image.
- The compose files keep the host bind mounts on application/{indexes,inputs,
vectors}, so an upgrade does not start with empty data. The move comes with
the packaging work, together with an upgrade note.
- The alias loader puts the real docsgpt spec back on the shared module object
after import (the import machinery stamped the alias spec on it, which made
importlib.reload rename the module and skip re-execution) and delegates
get_code/get_source/get_filename to the target loader, so
python -m application.<name> runs.
- Each legacy application.* task name is registered as its own task object,
a subclass carrying the old name. Registering the same object under two
keys made Celery's tracer log every run under whichever name it built last.
- The redbeat key prefix stays redbeat:docsgpt:; the three schedule_syncs
entries get stable names instead. redbeat tracks its static entries and
deletes the ones that vanish from beat_schedule at start-up, and rewrites the
task path of named entries in place, so neither a prefix bump nor a cleanup
pass is needed (checked against redbeat 2.4.2 with a seeded Redis).
The backend import package is now docsgpt, the name it will carry on PyPI;
application was far too generic to install into anyone's site-packages.
git mv plus a mechanical rewrite of every import, dotted string and path
reference: 734 Python files, the compose files, Dockerfile, workflows, docs,
setup scripts, devcontainer, k8s manifests, vscode config, pytest and coverage
config, .gitignore. Behaviour is unchanged.
Kept for one release:
- A top-level application package whose meta-path finder resolves
application.x.y to the already-imported docsgpt.x.y object, so old imports
and entry points (celery -A application.app.celery,
uvicorn application.asgi:asgi_app) keep working with a FutureWarning.
- Celery registers every application.* task name as an alias of its
docsgpt.* task on start-up, so messages queued by the previous release still
run. The redbeat key prefix moves to redbeat:docsgpt:v2: so schedule entries
the previous release wrote are left unread instead of firing twice.
The backend image builds from the repository root (docker build -f
docsgpt/Dockerfile .) so it can ship the alias package; a root .dockerignore
allow-lists docsgpt/ and application/ and keeps caches, local data, .env
files, the sample index files and the Dockerfile out. Compose and the image
workflows point at the new context.
The build and manifest jobs of both image workflows declare
environment: docker-hub, so the registry credentials can be scoped to it and
protection rules applied in the repository settings (the environment is
created on first use). The image namespace is the public arc53 the compose
files pull from, not the login secret, which now only authenticates.
zizmor flags a secret expanded inside with: or run:. The image workflows
put DOCKER_USERNAME in a job-level env and use that in tags, labels, cache
refs and the manifest loop; login-action keeps its username input.
- The frontend image ran the Vite dev server in development mode, so
.env.development supplied its defaults (notification banner, Google client
id, local API host). The static build only loads .env.production, so the
build stage now copies .env.development in as the baseline and the compose
files pass every VITE_* the app reads through from .env; the runtime script
skips empty values so a blank passthrough keeps the build-time default.
.dockerignore kept only the .local variants out.
- VITE_DISABLE_SOURCE_FE disables sources only when it is the string true.
- DoclingParser: find_spec raises when docling itself is absent; the install
hint now covers that path, with a regression test.
- verify_offline: direct tests for verify(); the PR image check builds and
verifies the -docling variant as well as slim.
- Workflows this branch adds or rewrites pin actions by commit, pass the
release tag through env instead of template expansion, and do not persist
checkout credentials.
- OCR guide no longer claims pre-built images never include docling.
Backend (arc53/docsgpt): 4.5 GB compressed -> 0.9 GB with both embedding
models and tiktoken baked in.
- torch/transformers gone from the default install (docling extra only).
- Ubuntu 24.04 ships python3.12: no deadsnakes PPA, no software-properties-
common; every pin is a wheel, so no gcc/g++/rust in the builder.
- COPY --chown and a prefetch that runs as the process user replace the
trailing chown -R, which duplicated the 600 MB model layer.
- .dockerignore keeps __pycache__, .coverage, local indexes and .env out.
- EXTRAS build arg (INSTALL_DOCLING kept as an alias); the docling variant
also bakes docling's layout/table/RapidOCR models (DOCLING_ARTIFACTS_PATH)
and tesseract, and drops only the discovery documents of Google APIs the
app never builds.
- FLASK_DEBUG env removed (unused); OCI labels added.
Frontend (arc53/docsgpt-fe): 302 MB Vite dev server -> 25 MB static build
behind nginx. VITE_* variables are injected at container start into
/config.js and read through src/env.ts, so the image no longer needs a
rebuild per deployment; docker-compose.yaml keeps hot reload via the dev
target.
Publishing: every release and develop build now pushes a slim tag and a
-docling tag (docling engine + models + tesseract). docker-compose-hub.yaml
takes DOCSGPT_IMAGE_TAG / DOCSGPT_IMAGE_VARIANT; docker-compose-standalone.yaml
runs the stack from pre-built images without a checkout and is attached to
each release. setup.sh selects the -docling variant for OCR instead of
requiring a local build. A new workflow builds the image on PRs that touch
it and runs verify_offline under --network none; lint checks the exported
requirements match uv.lock.
Enable code_executor and artifact_generator by default in chats (added to
DEFAULT_CHAT_TOOLS) — they load via the synthetic-id path user- and
conversation-scoped like scheduler, and persist artifacts (no user_tools FK).
Make read_document an internal agent-builtin flagged workflow_only so it appears
only in the workflow builder, not the classic agent picker or the Add-Tool
catalog (reuses the builtin synthetic-id path; still run-scoped and authz-gated).
Per decision, default-on code_executor runs sandboxed code without an approval
prompt (the sandbox is the trust boundary); this is documented in settings and
the threat model, and multi-tenant deployments should add per-tenant isolation
(Daytona / gVisor / egress policy).
Add code execution as an attack surface and an isolation threat: untrusted
LLM-authored code runs in the sandbox, and the self-hosted Jupyter runner is a
single trust domain (shared container/uid). Record the mitigations (approval
gating, state passed as data not code, scrubbed kernel secrets, 0700 workspaces,
network-layer egress) and that per-tenant isolation means the Daytona
per-session-VM backend or running the runner under gVisor.
* feat(frontend): add Modal primitive on Radix Dialog (P1.1)
Adds frontend/src/components/ui/modal.tsx — a thin wrapper around
the existing Dialog/DialogContent primitives that preserves the
legacy WrapperModal visual contract (bg-card, rounded-2xl, p-8,
blurred backdrop) while inheriting Radix's focus-trap, body-scroll
lock, and Esc handling. Always renders a DialogTitle (wrapped in
VisuallyHidden when hideTitle is set) so modals stop logging a11y
warnings on adoption. No consumers migrated yet.
* refactor(frontend): migrate ConfirmationModal to Modal primitive (P1.2)
Swaps WrapperModal for the new Radix-backed Modal so consumers
inherit focus trap, body scroll lock, and Esc-to-close. Footer
DOM order flipped from [Submit, Cancel] (flex-row-reverse) to
[Cancel, Submit] so tab order now matches visual order; visual
layout unchanged. Message renders as DialogTitle for proper
screen-reader announcement.
* refactor(frontend): inline DeleteConvModal into Navigation (P1.3)
DeleteConvModal was a thin Redux wrapper around ConfirmationModal
with a single consumer and a dead useOutsideAlerter on an unbound
ref. Inlined the direct ConfirmationModal call at the call site
and deleted the wrapper file.
* refactor(frontend): migrate 5 small modals to Modal primitive (P1.4)
Migrates FolderManagementModal, AddActionModal, JWTModal,
ShareConversationModal and SearchConversationsModal off WrapperModal
onto the Radix-backed Modal so they gain focus trap, scroll lock,
and consistent DialogTitle a11y. Footer DOM order normalised so
tab order matches visual order. JWTModal stays intentionally
uncloseable via isPerformingTask; P1.7 revisits.
Also wraps DialogDescription in VisuallyHidden when no description
is provided, silencing the Radix "Missing Description" console
warning that consumers without a subtitle were triggering.
* refactor(frontend): migrate 5 medium modals to Modal primitive (P1.5a)
Migrates AddToolModal, AgentDetailsModal, ConfigToolModal,
ImportSpecModal and MoveToFolderModal off WrapperModal. They now
inherit focus trap, scroll lock, Esc-to-close and consistent
DialogTitle a11y. Footers reordered to natural DOM order so tab
order matches visual order. AddToolModal's dead useOutsideAlerter
on an unbound ref removed.
* refactor(frontend): migrate 5 large modals to Modal primitive (P1.5b)
Migrates PromptsModal, CustomModelModal, MCPServerModal,
ScheduleFormModal and Upload off WrapperModal. These were the last
remaining consumers of the legacy modal wrapper outside of the
shared WrapperModalPropsType (kept temporarily for P1.9 cleanup).
CustomModelModal continues to set isPerformingTask while saving;
P1.7 revisits Esc behavior during locked submits.
* refactor(frontend): migrate AgentTypeModal to Modal primitive (P1.6)
AgentTypeModal was the last hand-rolled fixed-inset overlay in the
codebase. Swapping to Modal gives it focus trap, Esc-to-close,
body scroll lock and consistent DialogTitle a11y — none of which
the legacy overlay implemented.
* fix(frontend): let users dismiss CustomModel and Schedule modals during save (P1.7)
Drops isPerformingTask on CustomModelModal and ScheduleFormModal so
Esc / click-outside / the X button all close the modal while a
save is in flight. The Save button itself stays disabled so users
can't double-submit. SchedulesView.closeModal was also gating on
submitting; that lock is removed too. The in-flight network call
continues in the background.
JWTModal remains intentionally uncloseable — it gates app access
on auth, not a transient save state.
* style(frontend): normalise modal CTA radius to rounded-3xl (P1.8)
ConfigToolModal, JWTModal, ShareConversationModal and
ScheduleFormModal previously used rounded-full for their primary
CTAs while the rest of the modal suite uses rounded-3xl. Switches
the four outliers and pads font-medium where missing. Footer DOM
order across all migrated modals was already corrected to natural
order during P1.2 / P1.4 / P1.5, so no further reorderings here.
* chore(frontend): delete legacy WrapperModal (P1.9)
All 14 consumers were migrated to the Radix-backed Modal primitive
across P1.2-P1.6. Drops the legacy WrapperModal.tsx, the orphan
WrapperModalPropsType type re-export, and updates the stale z-index
comment in TimezoneCombobox to reference Modal's z-50.
* feat(frontend): add floating-label variant to ui/input (P2.1)
Extends the shadcn Input primitive with an optional label prop and
leftIcon/required/labelBgClassName slots so consumers can swap the
legacy components/Input.tsx without losing the peer-based floating
label UX. Existing bare-input usage is unchanged.
* refactor(frontend): migrate 9 callers off components/Input.tsx (P2.2)
Switches ToolConfig, PromptsModal, AddActionModal, JWTModal,
ToolsPopup, SourcesPopup, MultiSelectPopup, FilePicker and Upload
to the ui/input floating-label variant. Drops legacy knobs that
the audit flagged as cruft (colorVariant, borderVariant, textSize,
edgeRoundness); inputs converge on rounded-md and 1px borders.
The biggest visible delta is PromptsModal's prompt-name field —
pill -> rounded-md rectangle, intentional.
* chore(frontend): delete legacy components/Input.tsx (P2.3)
All 9 consumers were migrated in P2.2. Removes the legacy
component and the unused InputProps type from components/types.
* refactor(frontend): migrate 7 raw text inputs to ui/input (P2.4)
Swaps the page-level search inputs on Sources, Tools, CustomModels
and AgentsList, plus the inline new-folder input on AgentsList,
the FolderManagementModal field, and SearchConversationsModal,
onto the ui/input primitive. Page searches now use the floating
label / leftIcon slot. Complex per-method or workflow-editor inputs
deferred. Also clears the trailing-newline lint error in
modals/types after the WrapperModalPropsType deletion.
* feat(frontend): add destructive-outline button variant (P2.5)
Adds the red-outlined danger button pattern (border-destructive
text-destructive on transparent ground, filling to bg-destructive
on hover) so callers like "Delete All" CTAs can adopt the
primitive instead of hand-rolling the class string.
* refactor(frontend): migrate settings/ buttons to ui/button (P2.6)
Replaces 10 raw <button> elements across General, Sources, Tools,
CustomModels, Prompts and ToolConfig with the ui/button primitive.
General's Delete-All CTA adopts the new destructive-outline variant.
Tiny method-row buttons inside ToolConfig with bespoke 50px inline
widths are deferred to a later targeted pass.
* refactor(frontend): migrate agents/ buttons to ui/button (P2.7)
31 raw <button> elements across AgentsList, NewAgent, the schedules
view + form + run drawer, SchedulerToolCallCard, RunLog,
SharedAgentCard, and WorkflowPreview converted to the ui/button
primitive. NewAgent's Danger-Zone Delete CTA adopts the new
destructive-outline variant. AgentTypeModal's two type cards stay
raw — the lucide icon sizes would conflict with Button's SVG
selector — but pick up focus-visible ring classes for a11y.
WorkflowBuilder (18 buttons) and PromptTextArea deferred.
* refactor(frontend): migrate modal + small-component buttons to ui/button (P2.8)
52 raw <button> elements across 11 modals (ConfirmationModal,
FolderManagementModal, AddActionModal, ConfigToolModal,
ImportSpecModal, ShareConversationModal, AgentDetailsModal,
MCPServerModal, CustomModelModal, JWTModal, SearchConversationsModal)
and 10 small components (ActionButtons, CopyButton,
TextToSpeechButton, Help, DocumentPagination, SettingsBar,
ConnectorAuth, UploadToast, Accordion, Notification) converted to
the ui/button primitive. ConfirmationModal's danger variant now
uses the canonical destructive variant rather than a class string.
MoveToFolderModal (purple-hex inputs) plus all chat/file-tree
internals deferred.
* refactor(frontend): collapse 3 popups into MultiSelectPopover (P2.9+P2.10)
Adds frontend/src/components/MultiSelectPopover.tsx — a single Radix
Popover + cmdk Command-backed primitive supporting groups, search,
icons, loading, footer slot, and (selected-first) ordering. Migrates
MessageInput (Sources + Tools), NewAgent (Sources + Tools + Models)
onto it, then deletes MultiSelectPopup, SourcesPopup and ToolsPopup
(~803 LoC removed). The isChatToolVisible helper moves to
utils/toolUtils.ts with its tests preserved. Visual change: drops
the bespoke Material 3-layer shadow in favor of shadow-md.
* refactor(frontend): collapse 3 custom dropdowns onto shadcn primitives (P2.11)
Deletes Dropdown.tsx, DropdownMenu.tsx and DropdownModel.tsx
(~513 LoC) and migrates the 10 consumers (Hero, Sources, Prompts,
PromptsModal, Analytics, ToolConfig, General, ShareConversationModal,
Upload, NewAgent). Simple cases land on ui/select; action menus on
ui/dropdown-menu; the searchable prompts picker uses ui/popover +
ui/command. Inline edit/delete on prompts rows preserved via a small
combobox; variable menus in PromptsModal use ui/dropdown-menu.
* refactor(frontend): migrate Sidebar + ArtifactSidebar to ui/sheet (P2.12)
Deletes Sidebar.tsx and rewrites ConversationBubble to render the
citations panel directly via ui/sheet. ArtifactSidebar keeps its
public API but its overlay variant now uses ui/sheet instead of a
hand-rolled fixed-position overlay + manual click-outside, so it
inherits Radix's focus trap, Esc handling, and scroll lock.
* refactor(frontend): migrate ContextMenu to ui/dropdown-menu (P2.13)
Deletes ContextMenu.tsx (177 LoC) and migrates its 8 consumers
(ConversationTile, FolderCard, AgentCard, settings/CustomModels,
settings/Tools, settings/Sources, FileTree, ConnectorTree) to the
Radix-backed ui/dropdown-menu. Destructive items use the canonical
variant; each menu trigger uses stopPropagation so clicking the
3-dots no longer fires the parent row's onClick.
* refactor(frontend): retire the legacy color palette (P0.1+P0.2)
Migrates the last 13 consumers of legacy named-color tokens to
the semantic system (bg-primary, bg-muted, text-foreground,
border-border, etc.) and then deletes the ~60-token legacy
@theme block in index.css, including the invalid 5-digit
--color-just-black: #00000 entry. Three intentional visual
shifts: ToggleSwitch on-state moves from green to bg-primary,
PageNotFound CTA from the misnamed bg-blue-1000 to bg-primary,
and the user-message bubble gradient from medium-purple/slate-blue
to violet-500/violet-600.
* refactor(frontend): replace hardcoded purple hexes with semantic tokens (P0.3)
Removes #7D54D1 / #976af3 / #6A4DF4 / #563DD1 / #8C67D7 / #6F3FD1
/ #D9534F literals from ~15 tsx files, mapping each to bg-primary /
text-primary / border-primary / bg-destructive / hover:bg-primary/90.
The Spinner primitive drops its color prop and inherits currentColor
so it picks up the parent's Tailwind text class. Analytics chart
colors now read --primary at runtime via getComputedStyle on
document.body (where the .dark class lives) so dark mode renders
#976af3 instead of the light #7d54d1.
PromptsModal's bespoke #D9534F danger maps to bg-destructive.
MoveToFolderModal's purple-branded inputs and several toast banners
were also caught in the sweep.
* feat(frontend): add --font-mono token, drop inline IBMPlexMono styles (P0.4)
Defines a --font-mono token in @theme and points it at the existing
IBMPlexMono-Medium @font-face fallback chain. The 6 inline
style={{ fontFamily: 'IBMPlexMono-Medium' }} occurrences in
ConversationBubble's tool-call panels are replaced with the
font-mono Tailwind utility; .logs-table now references the token
too. Tokenises the mono surface so future consumers don't need
inline styles.
* feat(frontend): token-ize modal + toast shadows (P0.5)
Adds --shadow-modal and --shadow-toast tokens in @theme. The two
arbitrary shadow strings (the WrapperModal-era 4-40 modal shadow
and the 24-48 toast shadow) collapse to `shadow-modal` and
`shadow-toast` utilities across Modal, WorkflowBuilder's settings
panel, UploadToast and ToolApprovalToast. The one-off radial hover
halo in Upload.tsx stays inline (not part of the modal/toast set).
* refactor(frontend): collapse 49 arbitrary radii onto canonical scale (P0.6)
Maps every rounded-[Npx] (and its rounded-t-*/rounded-b-* variants)
to a Tailwind built-in: rounded-md/lg/xl/2xl/3xl/full. Includes
NewAgent's 11 panel sections (rounded-2xl), AgentCard/FolderCard
(rounded-2xl), Hero demo CTAs and message-input pills (rounded-full),
the answer/thought/user-message bubbles (rounded-2xl/3xl), code
blocks (rounded-md/xl), and the FileTree/ConnectorTree search
chrome. Closes out the audit's "six different radius scales"
finding.
* refactor(frontend): standardize type scale + fix font typos (P0.7)
Collapses ~80 arbitrary text-[Npx] utilities onto the canonical
Tailwind scale (text-xs/sm/lg/xl/2xl/3xl/4xl), fixes the
font-semi-bold typo in SharedConversation (rendered as font-normal
before), and removes the undefined font-inter class from 10 sites —
body already defaults to Inter via index.css. The largest visual
shift is text-[10px] -> text-xs (2px growth on tiny chip labels);
mid-range deltas are <=1px.
* style(frontend): soften popover/select/dropdown/command radii to rounded-xl
The pill-shaped (rounded-3xl, effectively fully rounded at h-9/h-10)
select triggers in Settings/Analytics/ToolConfig/NewAgent looked
mismatched against the shadcn-default rounded-md (6px) popover
content. Bumps the four ui content panels to rounded-xl (12px) so
the trigger -> popover transition reads as a single step on the
radius scale rather than an 18px jump.
* style(frontend): align Select popover to trigger width, merge Hero model picker
ui/select: switches default position from item-aligned to popper so
Radix exposes --radix-select-trigger-width on the popper container,
adds w-(--radix-select-trigger-width) so the popover width tracks
the trigger exactly, and drops the min-w-32 floor that was forcing
narrow triggers like the Analytics filter (w-[125px]) to render
3px wider than their triggers. Side-effect: Analytics dropdowns no
longer overlap the settings tab bar (popper anchors below).
Hero: pairs the trigger's data-[state=open]:rounded-b-none with
rounded-t-none + rounded-b-4xl + data-[side=bottom]:translate-y-0
on the popover so the two shapes merge into one continuous pill
when open.
* refactor(frontend): fold two skeletons into SkeletonLoader (P3.1)
Adds connectedState + filesSection variants to SkeletonLoader and
sweeps the existing variants from bg-gray-200/700/bg-gray-300/600
onto the semantic bg-muted / bg-muted-foreground/20 pair. Deletes
the two standalone files and migrates GoogleDrivePicker to the
variant API. One skeleton tone across the app.
* chore(frontend): drop legacy spinner SVGs + last raw animate-spin (P3.2)
Migrates Navigation, ShareConversationModal, TextToSpeechButton
and MultiSelectPopover off three SVG spinner assets onto the
currentColor Spinner component, then deletes assets/spinner.svg,
spinner-dark.svg and Loading.svg. Also replaces the last raw
animate-spin border-b-2 loader with Spinner.
* refactor(frontend): inline SVG components -> assets/*.svg?react (P3.3)
Deletes SendArrowIcon.tsx and RetryIcon.tsx. The send-arrow path
moves into assets/send.svg (overwriting the unused paper-plane
icon), the retry path into a new assets/retry.svg; both use
fill="currentColor" so consumers theme via Tailwind text classes.
MessageInput and ConversationMessages now import the SVGs via
?react. ConversationMessages drops a now-unused useDarkTheme hook
that was switching the retry icon's fill/stroke manually.
documentation-dark / no-files-dark / science-spark-dark variants
left in place — they're hand-tuned dark palettes, not pure inverts,
so collapsing them would regress visually.
* refactor(frontend): unify close icons on lucide X (P3.4)
Migrates the last three assets/exit.svg consumers (MessageInput
attachment pills, ArtifactSidebar split + sheet variants,
ConversationTile rename cancel) plus two inline-SVG X paths
(UploadToast dismiss, ToolApprovalToast dismiss) to lucide X.
Deletes assets/exit.svg. lucide X uses currentColor so the
filter dark:invert plumbing also goes away. ConversationTile's
bare clickable img becomes a proper button.
* refactor(frontend): merge Avatar + AgentImage into ui/avatar (P3.5)
Builds a single components/ui/avatar.tsx that subsumes both legacy
files: takes src/alt/fallbackSrc/className/imgClassName for the
smart-img case, and falls back to children passthrough for the
custom-node case (e.g. the user-question avatar in
ConversationBubble). All 6 consumers (Navigation, AgentCard,
SharedAgentCard, SharedAgent, ConversationBubble x5, ResearchProgress)
migrated, then Avatar.tsx and AgentImage.tsx deleted. The onError
robot-fallback behavior is preserved.
* refactor(frontend): promote ToggleSwitch/SettingsBar/Accordion/Table -> ui/* (P3.6)
Promotes four legacy components to shadcn-style primitives:
- ui/switch (Radix Switch) replaces ToggleSwitch; 7 callsites
migrate, including 3 inline hand-rolled toggles in NewAgent.
- ui/tabs (Radix Tabs) replaces SettingsBar; the settings page
keeps its mobile horizontal-scroll arrow wrapper.
- ui/accordion (Radix Accordion) replaces Accordion; consumed by
ConversationBubble tool-call panels.
- ui/table (plain <table>) replaces Table; tokenises bg-gray-100
-> bg-muted and borders -> border-border; 3 tree-browser
consumers swap imports.
Adds @radix-ui/react-switch / -tabs / -accordion as explicit deps
(previously transitive via the radix-ui meta-package).
* refactor(frontend): dedupe FileTree + ConnectorTree (P3.7)
Extracts a shared TreeBrowser into components/tree/ that handles
directory state, breadcrumb header, search dropdown, table render,
Chunks pickup, row-menu API and an SSE-terminal-wait hook. The
two wrappers shrink to thin shells holding only what differs: file
upload + delete flow on FileTree, sync flow on ConnectorTree. The
Sources.tsx consumer API is unchanged. 1895 -> 1391 LoC (~27%
reduction).
* style(frontend): unify settings card padding to p-5 (P4.1)
Sources tiles were p-3, Tools tiles p-6, CustomModels p-5. Picks
p-5 as the median and applies to Sources and Tools so the three
tile families breathe the same way.
* style(frontend): promote Settings Prompts Add to filled CTA (P4.2)
The Add prompt button was visually outlined-as-primary (variant=outline
+ border-primary/text-primary/hover:bg-primary overrides). Adding a
prompt is the page's main action — drop the overrides and use the
canonical default (filled bg-primary) variant so the CTA reads as
primary at a glance.
* style(frontend): add dark variants to WorkflowBuilder palette tiles (P4.3)
The five node-picker tiles (AI Agent purple, End green, Note yellow,
Set State blue, If/Else orange) used bg-{color}-100 with no dark:
companion, leaving them blindingly bright on the dark canvas. Pairs
each with bg-{color}-900/40 + dark:text-{color}-300 so they sit on
the dark workflow background.
* refactor(frontend): dedupe METHOD_COLORS + extract NARROW_CELL (P4.4)
ToolConfig and ImportSpecModal both declared an identical
METHOD_COLORS map for HTTP-verb pills. Moves the map + a
getMethodColorClass helper into utils/httpMethodColors.ts and
points both consumers at it.
ToolConfig also had 9 identical style={{ width: '50px', ... }}
inline blocks on table cells. Replaces them with a NARROW_CELL
Tailwind constant. The `!` suffix is required because the
codebase's @utility table-default rule otherwise out-specifies
the utility classes — inline styles were load-bearing for that
reason.
* style(frontend): drop MoveToFolderModal inline fonts + tokenize hover (P4.5)
Removes the inline fontFamily 'Inter' / 'Segoe UI' overrides — body
already inherits Inter via index.css — and collapses the inline
font-size/line-height/letter-spacing on the title into Tailwind
utilities (text-2xl leading-7 tracking-[0.15px]). Replaces the
breadcrumb hardcoded text-[#59636E] with text-muted-foreground and
swaps the chevron's hover:bg-[#FFFFFF2B] for hover:bg-accent.
* refactor(frontend): migrate ToolConfig method-row buttons to ui/button (DEF.1)
13 raw <button> elements left over from the P2.6 settings sweep
(method-row trash inside NARROW_CELL, rename confirm/cancel,
Add/Cancel/Add-new footers in the Properties + Headers tables)
now go through the ui/button primitive. Action-row trash retains
its stopPropagation so clicking the icon doesn't collapse the row.
* refactor(frontend): migrate conversation/* buttons to ui/button (DEF.2)
21 raw <button> elements across ConversationBubble (15),
ConversationMessages (2), ConversationTile (2), SharedConversation
(1) and ResearchProgress (1) now go through ui/button. Includes
question collapse/edit, edit submit/cancel, like/dislike feedback,
copy / regen / retry, citation pills, tool-call approve/deny,
sources/thought/tool-calls accordions, scroll-to-bottom and the
shared-conversation CTA. All stopPropagation handlers preserved.
* refactor(frontend): migrate MessageInput buttons to ui/button (DEF.3)
Migrates the 7 raw <button> elements in the 1768-LoC chat input
(attachment chip remove, Sources/Tools popover triggers + footer
upload CTA, voice/mic toggle, stop-streaming, send/submit) onto
ui/button. The 3 remaining <input> elements are file/dropzone
inputs (react-dropzone hidden + attach + voice picker) and are
intentionally left as-is.
* refactor(frontend): migrate WorkflowBuilder buttons + inputs (DEF.4)
17 of 18 raw <button> elements migrated to ui/button (back-to-all,
pencil-edit, settings Done, toolbar Details/Access-Details/Delete/
Preview/save, error-alert close, node-config close, state-op add/
delete, condition case add/delete, simple/advanced segmented control,
delete-node). The 1 remaining raw button is the custom toggle
switch for allow_system_prompt_override which uses a non-button
animated UI.
7 of 8 raw <input> migrated to ui/input (workflow name, node title,
output variable, target variable, case name, simple-mode var/value).
The 1 remaining raw input is the stream_to_user checkbox.
Palette tiles, drag-and-drop, React Flow node interactions all
preserved.
* refactor(frontend): migrate utility-component buttons to ui/button (DEF.5)
25 raw <button> elements across 7 small utility components migrated
to ui/button: Chunks (8), MermaidRenderer (5, low-risk path keeps
the custom download wrapper), GoogleDrivePicker (3),
FilePicker (3), tree/TreeBrowser (2), workflow PromptTextArea (2),
ArtifactSidebar (2). All onClick/disabled/aria/stopPropagation
preserved; MermaidRenderer's brand colors and Drive-picker's
#A076F6 brand override kept inline.
* refactor(frontend): migrate page-level buttons to ui/button (DEF.6)
27 raw <button> elements across Navigation (6), preferences
PromptsModal (5), Upload (3), settings Prompts (3), MoveToFolderModal
(8) and ToolApprovalToast (2) migrated to ui/button. Includes the
sidebar collapse / new-chat / mobile-hamburger / agent-pin row in
Navigation, both Add and Edit prompt modal flows, the breadcrumb +
folder-row + Cancel/Move CTAs in MoveToFolderModal, Upload back
chevron / advanced toggle / Train submit, the toast Dismiss + Review
pair, and the Settings Prompts popover trigger + per-row pencil/trash
buttons.
* refactor(frontend): final raw <input> sweep onto ui/input (DEF.7)
25 text/search/number inputs migrated to ui/input across:
ToolConfig (14 method-row + search), ImportSpecModal (1 spec URL),
NewAgent (agent name + 2 advanced number limits), Chunks (2
searches), MoveToFolderModal (new-folder pill), ConversationTile
(inline rename), ConversationBubble (tool-call denial reason),
tree/TreeBrowser (file search with rounded-t-3xl switch), and the
workflow PromptTextArea variable search.
11 raw <input> intentionally left: checkboxes (4), dropzone/file
inputs (3 - controlled by react-dropzone), the ScheduleFormModal
borderless title input (1), and the ui/input + ui/time-picker
primitives themselves (2).
Per-site className overrides keep method-row inputs tight (h-auto
rounded-lg px-2 py-1 shadow-none), borderless inline renames, and
the MoveToFolderModal primary-purple pill.
* chore(frontend): drop orphan dark-variant SVG assets (DEF.8)
Removes 5 unused color-variant SVGs that no consumer imports:
clock-purple, clock-white, monitoring-purple, monitoring-white,
white-trash. The remaining hand-tuned dark variants (documentation
pair, no-files pair, science-spark pair) are intentionally kept
because their consumers use <img> and collapsing them onto a single
currentColor SVG would require a JSX refactor outside this scope.
* fix(a11y): make AgentCard + FolderCard keyboard accessible (P5.1)
Both wrapped their entire body in a bare <div onClick> with no
keyboard handler — invisible to keyboard and screen-reader users.
Adds role="button", tabIndex={0}, Enter/Space onKeyDown, and a
focus-visible ring (focus-visible:ring-ring/50 ring-[3px]) so
the cards are actually focusable. AgentCard only takes the role
when its status is 'published' so unpublished cards stay
non-interactive. FolderCard exposes aria-pressed for its
expanded state.
* fix(a11y): add focus-visible rings to remaining outline-none sites (P5.2)
8 textareas/inputs without replacement focus visuals (PromptsModal
content, ToolConfig rename pair, NewAgent description + system
prompt, workflow PromptTextArea, ConversationBubble edit-query,
Chunks editor) now pair their outline-none with the canonical
focus-visible:ring-ring/50 focus-visible:border-ring focus-visible:
ring-[3px] pattern. 7 callsites in ScheduleFormModal +
WorkflowBuilder upgraded from focus: to focus-visible: so the
ring only shows on keyboard focus, not on mouse click.
* fix(a11y): gate changelog banner off /share/ and /shared/ (P5.3)
The Notification banner used to render on every route as long as
showNotification was true. Embedded / public share pages
(/share/<id>, /shared/agent/<id>, /shared/...) shouldn't carry
product chrome. Adds a useLocation() check in App.tsx so the
banner only renders on application routes.
* feat(frontend): sidebar collapse -> icon rail on desktop (P6.1)
Replaces the previous "sidebar slides off-screen, only a tiny
floating header remains" collapse behaviour with a vertical
56px-wide icon rail at the left edge on lg+ viewports. The rail
surfaces the main nav actions (open-sidebar, new-chat when
applicable, search, agents, settings). Main content shifts to
lg:ml-14 when collapsed and lg:ml-72 when expanded so it never
underlaps the rail. Mobile / tablet behaviour is unchanged —
they still use the hamburger drawer.
* fix(frontend): lift changelog banner above mobile input bar (P6.2)
The Notification banner used uniform bottom-6 (24px), which on
mobile sat squarely over the Sources / Tools / Attach button row
(37px overlap into the textarea). Switches to bottom-24 sm:bottom-6
so the banner sits ~96px above the bottom on mobile (clearing the
input bar) and stays at 24px on tablet+. Now only a ~11px sliver
grazes the textarea's top border on mobile, with no controls
occluded.
* refactor(frontend): extract MessageInput sub-components (P6.3)
Splits the 1919-LoC MessageInput.tsx into 5 focused sub-components
under components/message-input/: AttachmentChipList (the file-chip
strip above the textarea), AttachFileButton (paperclip + hidden
file input), SourcesTrigger (pill + MultiSelectPopover for source
docs), ToolsTrigger (pill + lazy-loaded MultiSelectPopover for
tools), and MicButton (idle/recording/transcribing tri-state).
Parent shrinks to 1686 LoC; ~233 lines of UI logic move to 6 new
files. State stays in the parent — sub-components are props-only.
The textarea+send/stop button and the voice-capture plumbing
intentionally remain inline (would require prop-drilling /
hook-lifting beyond the conservative bar for this pass).
* docs(agents): document the icon strategy for new code (P6.4)
Adds an "Icons" subsection under the frontend coding rules in
AGENTS.md. Codifies the three current sources (lucide-react, SVG
?react components, SVG <img>) and picks lucide-react as the default
for new UI affordances, SVG ?react for brand/domain illustrations
that need currentColor theming, and discourages <img src=...> for
new icons. Notes the three remaining hand-tuned dark-variant SVG
pairs that intentionally stay paired (documentation, no-files,
science-spark) because they're multi-color illustrations, not pure
inverts.
* fix(frontend): align Settings Prompts Add button height to dropdown trigger
The Add button was rendering 10px shorter (36px) than the
Active-Prompt PopoverTrigger (46px) because the Button primitive's
default h-9 was capping it. Adds h-auto + py-3 so padding drives
the height, plus border border-transparent so the 1px border the
trigger has is counted on both — taking Add from 36 -> 46px and
closing the visible bottom-edge mismatch.
* feat: auto version release
* fix(frontend): clean up workflow-builder header duplication
The toolbar was rendering the workflow name twice (once in the
AgentPageHeader breadcrumb and once in a standalone title block)
plus the description awkwardly stacked next to the tab strip. Drops
the title block on the owner view (breadcrumb already shows the
name); the pencil edit button stays but is now always visible
instead of hidden until hover, and gains a "name — description"
tooltip so the description is still reachable at a glance. Non-
owners keep the title block since they don't see the breadcrumb.
* fix: tabs
* fix: breadcrumb and tabs
* fix: remove details btn on agent workflow
* fix: dropdown arrow
* fix: modal clicks
* fix: rounded search
* fix: mini issues
* fix: pin versions
* (chore) fe lint-fix
* fix: rounded search on source, password autocomplete, accordions in chat
---------
Co-authored-by: ManishMadan2882 <manishmadan321@gmail.com>