Skip to content

Make the run-it-yourself answer findable, and true - #206

Merged
thalida merged 14 commits into
mainfrom
feat/issue-205-run-locally-findable
Aug 22, 2026
Merged

Make the run-it-yourself answer findable, and true#206
thalida merged 14 commits into
mainfrom
feat/issue-205-run-locally-findable

Conversation

@thalida

@thalida thalida commented Aug 22, 2026

Copy link
Copy Markdown
Owner

Closes #205

People kept asking whether codecity can open private or local repos. The landing already answered them, in 11px type, tinted to match the card it sat on, in the helper-text slot under an input, and it said something that wasn't quite true.

The answer was wrong

api/ has no git credential support, so clones are anonymous. Running codecity yourself does not open a private remote URL. The only path, for private repos and local folders alike, is clone it yourself and mount the folder. The old copy said "Private and local repos need codecity running on your own machine", which sends people to a docker run that cannot open the repo they just failed to open.

And nobody saw it

--cc-font-xs (11px, the smallest type on the page) in --cc-accent-bg-soft (accent at 10% alpha) over --cc-glass-fill, deliberately shaped to read as part of the input group. It also vanished the moment the field read as a URL, so it was gone for the whole act of pasting a private repo URL.

What ships

The landing answers in the hero. Two lines, one type step, no glyph, whenever this instance can't open a local folder:

Yes, private and local repos work
Clone a repo locally, then run codecity on your machine.

The hero is grouped. It was six siblings at one even 12px gap, with the wallpaper caption sitting between the tagline and the cues it introduces. Three groups now at 24px with 12px inside them (identity, pitch, scope), caption dropped to the foot of the column.

The notice collapsed from eight states to three. It used to branch on hosted and allowLocal and reason. hosted says which deployment this is; the message is about whether this instance can open a local folder, so keying on it made the same sentence move between the hero and the field slot. Now placement is decided by what happened (resting statement in the hero, failure under the field) and the remedy by one boolean:

Couldn't open that path.  Run codecity with a volume mount to access local repos.
[ Run it yourself v ]  Setup guide

Couldn't reach that repo.  If it's private, clone it yourself, then run codecity locally.
[ Run it yourself v ]  Setup guide

Couldn't reach that repo.  If it's private, clone it yourself and open the folder.
$ git clone <src>                                     Setup guide

NoticeReason.Standing is gone (the band owns it), and with it the notice's second visual variant and its glyph: it only answers failures now, so it is always an alert. hosted leaves the frontend entirely, though CODECITY_HOSTED stays in the API and the config table.

Every state hands over a command, never just a link. The old copy told an unmounted local instance to "turn on local paths" and stopped, but -e CODECITY_ALLOW_LOCAL_REPOS=1 plus a -v is turning them on, and it is the same command a visitor needs. Where the repo is known, the disclosure carries the clone and the run together, in that order.

Also

  • README: Run it yourself leads with the mounted command; the bare one is a Public repos only aside. Local directories dissolves into it, so LOCAL_DOCS_URL and a component-private RUN_DOCS_URL collapse to one anchor.
  • SetupGuideLink: three surfaces linked the same README section under three names (See docs, Full setup, See local setup). One component owns the href and the name.
  • MetaLine: about is now GitHub. Same href, same title, same three items; changes the city footer too.

Checks

Full pre-push gate green (7/7) on every commit. 2153 frontend tests. Each new guard was verified to go red against the behavior it protects: the plain docker run, an always-open disclosure, the hosted "turned off" wording, the band removed, the caption back inside the pitch, a blocked path told to clone a folder it already has, and a folder-reading instance told to go run codecity. Contrast computed from the OKLCH tokens rather than eyeballed; the tightest was the command hint at 4.55:1, moved from secondary to primary.

🤖 Generated with Claude Code

thalida and others added 4 commits August 22, 2026 01:18
Running codecity yourself was documented as a plain `docker run`, with the mount
that makes it useful buried two headings deeper under Advanced setup. That reads
as "run this and paste your private URL", which cannot work: the server holds no
git credentials and clones anonymously, so a private repo needs exactly the mount
a local folder does.

Run it yourself now leads with the mounted command, and the bare one is a
"Public repos only" aside under it. Local directories dissolves into that section
rather than duplicating it, so LOCAL_DOCS_URL and the component's own
RUN_DOCS_URL collapse into one constant pointing at #run-it-yourself.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… see

Three problems, one component. The copy said private and local repos "need
codecity running on your own machine", which is not enough: running it does not
open a private URL, cloning it yourself and mounting the folder does. It now says
that, and carries the mounted `docker run` behind a Run it yourself disclosure so
the answer is one click rather than one link away. Full setup still goes to the
README for the rest.

Hosted, a typed local path opened with "Local paths are turned off", implying a
switch codecity.io does not have. It states the deployment's limit instead.

And the styling was camouflage by construction: the input's own shape at
--cc-font-xs in a 10%-alpha accent wash, sitting where helper text sits. It is a
callout now, a step up the type scale on a fill you can see, which is what the
comment about reading "as part of the input group" was buying at the cost of
being read at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The hero was six siblings at one even 12px gap, so nothing belonged to anything
and the wallpaper caption sat between the tagline and the cues it introduces,
splitting the pitch in half. It is three groups now at 24px with 12px inside
them: identity, pitch, scope, with the caption dropped to the foot of the column
where a caption goes.

Scope is the new part: two lines, one type step, no glyph, saying that private
and local repos work and linking the setup. No icon on purpose, since the four
layer-coloured cues own that left edge and a fifth there reads as a fifth cue in
a box.

Hosted, this replaces the standing notice under the field rather than joining it.
The same sentence twice on one screen, a column apart, is how neither gets read;
the field slot keeps the failures, which are the states that want the command.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
"about" read as a page describing the project. It is the source on GitHub, which
is also where the run-it-yourself instructions live, so it says GitHub. Same
href, same title, same three items: only the word changes, on both the landing
and the city footer.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@thalida thalida linked an issue Aug 22, 2026 that may be closed by this pull request
thalida and others added 10 commits August 22, 2026 01:44
The message moved around. The hero band keyed off `hosted`, which says which
deployment this is, while the thing being communicated is whether this instance
can open a local folder. So a self-hosted instance without a mount lost the band
and got the same sentence under the field instead: one fact, two places, decided
by a flag unrelated to it. The band keys off `allowLocalRepos` now, and where the
message lives is decided by what happened rather than by which deploy it is.
Standing statement in the hero, failure under the field, always.

That makes `NoticeReason.Standing` unreachable, so it goes, and with it the
notice's second visual variant: this only ever answers a failure now, so it is
always an alert. `hosted` leaves the frontend entirely.

The remaining branch is one boolean. Either a folder you already have is
openable here, or you need an instance where it is, and both hand over the
command rather than a link. The old copy told an unmounted local instance to
"turn on local paths" and stopped there, but `-e CODECITY_ALLOW_LOCAL_REPOS=1`
plus a `-v` IS turning them on, which is the same command a visitor needs.
Unreachable knows what failed, so its disclosure carries the clone and the run
together, in that order.

Copy is one sentence per failure, because the two want different things: a repo
you don't have has to be cloned, a folder you already have only has to be
mounted. Merging them had a blocked path being told to clone something already
on its own disk, which the guard now catches.

CODECITY_HOSTED stays in the API and the config table, unused by the app.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
"See docs" in one state and "Full setup" in the other, both pointing at the same
README section. Setup guide in both, which lets DocsLink drop its children and
just be the link.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three surfaces linked the same README section under three names: "See docs",
"Full setup" and, in the scan menu, "See local setup". SetupGuideLink owns the
href and the name together, so the next rename is one edit rather than a search.

The notice loses its glyph and runs what failed into what fixes it, so a blocked
path is two rows instead of four. The red fill and role=alert already say it is a
failure; the icon was a third telling. Padding comes in a step to match.

The landing band links "run codecity" rather than the whole clause, and drops
"with that folder mounted": the guide on the other end of that link is what
explains mounting, and the band is the pitch, not the instructions.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
"Mount that folder and it can" was an imperative for something the screen it sits
on cannot do: there is no mounting from a text field, and "it" was reaching back
past a sentence boundary for codecity. It states the rule instead, which is also
what makes the button and the guide beside it make sense.

The band clones a repo locally and runs codecity on your machine, rather than
cloning "one" and running it nowhere in particular.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
One was "Couldn't reach that repo", the other named codecity as a subject in the
present tense. Same clipped past tense for both, and "path" rather than "file"
because a path is what the field took.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
"Clone it yourself and open the folder" was one string for both, which only read
right where folders are already openable. Where they are not, the clone lands
somewhere nothing can read it, so it says to run codecity locally too.

One function rather than one string per reason: the remedy turns on what the
instance can do with the clone, and a blocked path still states the rule.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
"Run codecity on your machine" is already true for whoever ran it without a
mount, which is exactly the person seeing this. Naming the volume mount reads as
the next step for them and as the whole setup for a visitor, so one sentence
serves both without the notice needing to know which it is talking to.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Anyone at "Run it yourself" already knows a container cannot see their disk, so
the two paragraphs explaining that go. What is left is the flag, the mount, and
three steps.

Matching paths on both sides of the `-v` is a convenience, not a requirement:
resolve_local resolves inside the container, so any mount point works as long as
you type that path. It reads as the easy option rather than a rule now.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The old line said private repos need codecity on your own machine, which is what
the app used to say and is only half true: running it is necessary, cloning the
repo yourself is the rest. Naming locally cloned repos carries both, and it
retires the bullet underneath that was spelling out the missing half.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Retired one commit ago as redundant with "locally cloned repos", which was wrong:
that line covers the clone but not the mount, and the mount is the half people
miss. Back, naming both.

The `-v` bullet drops its trailing clause.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@thalida
thalida merged commit d9529f6 into main Aug 22, 2026
5 checks passed
@thalida
thalida deleted the feat/issue-205-run-locally-findable branch August 22, 2026 16:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Landing: make the run-it-yourself answer findable

1 participant