← Back to list

Syncing Local Code to a Live Web App

One of the main features of https://phibelle.studio/ is the ability to write code online and have things change in real time right away.

Nabil Mansour · 2026-02-16 21:07 · 0 claps · 4.0 min read
#convex #clerk-auth #r3f #engine #cli
Open on Medium ↗
Wiki topics: GEN · Genomics & Sequencing 🌐 · Web Development

Syncing Local Code to a Live Web App

One of the main features of https://phibelle.studio/ is the ability to write code online and have things change in real time right away.

Coding online with Phibelle

Coding online with Phibelle

Issue was that no matter how much I would try to make the coding experience better in the engine’s code panel, my local environment of using cursor will always beat it. I assumed this is also the case if someone uses neovim, open code, claude code, or the plethora of coding environments that currently exists now.

So I had to figure out how exactly would I allow users to change the code on their scenes in the deployed web app from their local machine. This issue has many considerations to keep in mind like auth, real time changes, and just general developer experience.

So I broke the problem down into smaller problems:

  1. How can one authenticate who they are from the CLI with a web app
  2. How can one make changes to the DB of the web app from their local environment.
  3. How can one make real time changes to the web app based on changes in the DB.

Each one of these sub-problems can seem challenging at first, especially to someone who has never touched CLI tooling like me, but overall, I have found it to be a far simpler problem to solve than most things. Let’s start with how I authenticate users.

Authentication

Phibelle uses https://clerk.com/ for authentication and one specific feature clerk has is the [getToken](https://clerk.com/docs/reference/javascript/session#get-token) command which retrieves the current sessions token (JWT) that I can then use in any DB changes.

One problem is just getting the token itself from the web app to the CLI, and what I have found to be the best approach is to simply open a port on the user’s end, and open the browser for the user to a page that will send the token to that specific local host port.

export function waitForToken(): Promise<string> {
  return new Promise((resolve) => {
    const server = http.createServer((req, res) => {
      const url = new URL(req.url!, `http://localhost`);
      const token = url.searchParams.get("token");

      res.setHeader("Access-Control-Allow-Origin", "*");
      res.setHeader("Access-Control-Allow-Methods", "GET");

      if (token) {
        res.writeHead(200, { "Content-Type": "text/html" });
        res.end("Token received");
        server.close();
        resolve(token);
        setToken(token);
      } else {
        res.writeHead(400);
        res.end("Missing token");
      }
    });

    server.listen(PORT, () => {
      console.log("Opening browser to authenticate...");
      open(`${BASE_URL}/cli-token`);
    });
  });
}

Web app sending the token to the CLI

Web app sending the token to the CLI

One thing to consider though is that the token could expire. The best approach I have found to this is to simply fetch the latest token every time the CLI is called. I am not sure if this is the best approach out there, but it does resolve this problem and keeps the code simple for now.

DB changes

With the token in hand, we can now make DB changes. Phibelle uses https://www.convex.dev/ for the file and data base hosting and they provide a javascript client that can pull and push changes as well as subscribe to changes when needed.

I easily make a subscribeToQuery , queryOnce , and mutateOnce functions that can be used within the CLI. These functions imitate the behaviour of useQuery and useMutation in React, but for the CLI tool.

export function createConvexClient(): ConvexClient {
  const token = getToken();

  if (!token) {
    throw new Error("Not authenticated. Please run 'phibelle login' first.");
  }

  const client = new ConvexClient(CONVEX_URL!);

  client.setAuth(() => Promise.resolve(token));

  return client;
}

export function subscribeToQuery<Args extends Record<string, any>, Result>(
  query: any, // Query reference from api
  args: Args,
  callback: (result: Result) => void
): () => void {
  const client = createConvexClient();

  return client.onUpdate(query, args, callback);
}

export async function queryOnce<Args extends Record<string, any>, Result>(
  query: any,
  args: Args
): Promise<Result> {
  const client = createConvexClient();

  try {
    return await client.query(query, args);
  } finally {
    await client.close();
  }
}

export async function mutateOnce<Args extends Record<string, any>, Result>(
  mutation: any,
  args: Args
): Promise<Result> {
  const client = createConvexClient();

  try {
    return await client.mutation(mutation, args);
  } finally {
    await client.close();
  }
}

Real time collaboration

With all this done, one problem remained. A scene is defined as a JSON in Phibelle and the link of the JSON is stored the DB. useQuery will identify when this link changes in the DB, but the real question is how do I know which session updated the DB? The reason this is important is because you can get into an infinite loop where the current session that saved changes will load the changes it saved: causing the session to save the loaded changes which loads the changes which saves the changes which loads the changes…

This is bad and completely breaks how the system works. To remedy this, we can easily just add a lastModifiedSessionId which allows us to know which session was the one that was making the changes. This ID can be made with crypto.randomUUID() and is stored when the session is first opened.

So, the CLI can have its own session, and the web app that is open on the user’s browser can have another session. Then we simply check if the update to the DB is coming from a different session, and if so, we load the new data.

This also gives us the added benefit of having multiple browsers open with the same web page, and having each update according to the changes in other sessions.

[embed]

With all of this we can finally do changes on our local machine and have that update on the web app.

[embed]

Conclusion

Thank you for reading this article. If you have found it useful and have any questions, you can contact me by sending me a message on X https://x.com/nabilnymansour or through my website https://nabilmansour.com/

And if you would to check out these changes yourself. They are currently live on https://phibelle.studio/

Cheers!


메타데이터
post_id
802a2fc75782
slug
editing-code-on-a-web-app-locally-802a2fc75782
url
https://medium.com/@nabilnymansour/editing-code-on-a-web-app-locally-802a2fc75782
canonical_url
https://medium.com/@nabilnymansour/editing-code-on-a-web-app-locally-802a2fc75782
author_url
https://medium.com/@nabilnymansour
status
ok
fetched_at
2026-07-15 04:16:48