Quick Code Editing in the Browser: VSCode Web Integration Practice
After AI finishes analyzing code, how can you immediately open an editor in the browser to make modifications? This article shares practical experience from integrating code-server in the HagiCode project, achieving seamless connection between AI assistant and code editing experience.
Background
In the era of AI-assisted programming, developers frequently need to quickly view and edit code. The traditional development workflow is: open the project in a desktop IDE, locate the file, edit, save. But in some scenarios, this workflow feels somehow off.
Scenario 1: Remote Development. When using an AI assistant like HagiCode, the backend may run on a remote server or container, making project files inaccessible locally. Every time you need to view or modify code, you need to connect via SSH or other means—the experience is fragmented. It feels like wanting to see someone but being separated by a thick pane of glass: you can see but can't touch.
Scenario 2: Quick Preview. After the AI assistant analyzes code, users may just want to quickly browse a file or make minor modifications. Launching a full desktop IDE feels heavy-weight; a lightweight editor within the browser better fits the "quick view" use case. After all, who wants to make a big fuss just to take a glance?
Scenario 3: Cross-device Collaboration. When working across different devices, an in-browser editor provides a unified access point without needing to configure a development environment on each device. This saves time—after all, life is short, why repeat the same work?
To address these pain points, we integrated VSCode Web into the HagiCode project. This enables seamless connection between AI assistant and code editing experience—after AI analyzes code, users can immediately open the editor in the same browser session to make modifications without switching applications. This experience, well, it's like it's there when you need it.
About HagiCode
The solution shared in this article comes from our practical experience in the HagiCode project. HagiCode is an AI-driven code assistant designed to improve development efficiency through natural language interaction. During development, we found that users frequently need to quickly switch between AI analysis and code editing, which prompted us to explore how to directly integrate the editor into the browser.
Project URL: github.com/HagiCode-org/site
Technology Selection: Why code-server?
Among the many VSCode Web solutions, we chose code-server. This decision involved several considerations:
Complete Functionality. code-server is the web version of VSCode, supporting most features of the desktop version, including the extension system, intelligent code completion, debugging, and more. This means users can get an editing experience in the browser that's close to the desktop version. After all, who wants to compromise on functionality?
Flexible Deployment. code-server can run as a standalone service and also supports Docker containerized deployment, fitting well with HagiCode's architecture. Our backend is written in C#, the frontend is React, and we communicate with the code-server service via REST API. It's like building blocks—each piece has its place.
Secure Authentication. code-server has a built-in connection-token mechanism to prevent unauthorized access. Each session has a unique token, ensuring only authorized users can access the editor. Security is something you only appreciate once you have it.
Architecture Design
HagiCode's VSCode Web integration adopts a front-end and back-end separation architecture.
Frontend Service Layer
The frontend encapsulates interactions with the backend through vscodeServerService.ts:
// Open project
export async function openProjectInCodeServer(
id: string,
currentInterfaceLanguage?: string,
): Promise<VsCodeServerLaunchResponseDto>
// Open vault
export async function openVaultInCodeServer(
id: string,
path?: string,
currentInterfaceLanguage?: string,
): Promise<VsCodeServerLaunchResponseDto>
The difference between these two methods is: openProjectInCodeServer is for opening an entire project, while openVaultInCodeServer is for opening a specific path in a Vault. For MonoSpecs multi-repository projects, the system automatically creates workspace files. Clear division of labor—each does its job, and that's enough.
Backend Service Layer
The backend's VaultAppService.cs implements the core logic:
public async Task<VsCodeServerLaunchResponseDto> OpenInCodeServerAsync(
string id,
string? relativePath = null,
string? currentInterfaceLanguage = null,
CancellationToken cancellationToken = default)
{
// 1. Get settings and check if enabled
var settings = await _vsCodeServerSettingsService.GetResolvedSettingsAsync(cancellationToken);
if (!settings.Enabled) {
throw new BusinessException(VsCodeServerErrorCodes.Disabled, "VSCode Server is disabled.");
}
// 2. Get vault and resolve launch directory
var vault = await RequireVaultAsync(id, cancellationToken);
var launchDirectory = ResolveLaunchDirectory(vault, relativePath);
// 3. Ensure code-server is running and get runtime information
var runtime = await _vsCodeServerManager.EnsureStartedAsync(settings, cancellationToken);
// 4. Resolve language settings
var language = _vsCodeServerSettingsService.ResolveLaunchLanguage(
settings.Language,
currentInterfaceLanguage);
// 5. Build launch URL
return new VsCodeServerLaunchResponseDto {
LaunchUrl = AppendQueryString(runtime.BaseUrl, new Dictionary<string, string?> {
["folder"] = launchDirectory,
["tkn"] = runtime.ConnectionToken,
["vscode-lang"] = language,
}),
ConnectionToken = runtime.ConnectionToken,
OpenMode = "folder",
Runtime = VsCodeServerSettingsService.MapRuntime(
await _vsCodeServerManager.GetRuntimeSnapshotAsync(cancellationToken)),
};
}
The responsibilities of this method are clear: check settings, resolve paths, start service, build URL. The ResolveLaunchDirectory method performs path security checks to prevent path traversal attacks. Code is like poetry—each line has its own rhythm.
Automatic Runtime Management
The backend manages the code-server process through VsCodeServerManager:
- Check process status
- Automatically start stopped services
- Return runtime snapshots (port, process ID, startup time, etc.)
This design allows the system to automatically handle the code-server lifecycle, and users don't need to manually manage service processes. After all, life is already complex enough—automate what you can.
Language Following Mechanism
HagiCode supports multilingual interfaces, and code-server needs to follow this setting as well. The system supports three language modes:
-
follow: Follow current interface language -
zh-CN: Fixed Chinese -
en-US: Fixed English
The language is passed to code-server via the URL parameter vscode-lang, ensuring the editor language stays consistent with the HagiCode interface. Language feels comfortable when unified.
MonoSpecs Multi-repository Workspace
For MonoSpecs projects (mono-repos containing multiple sub-repositories), the system automatically creates a .code-workspace file:
private async Task<string> CreateWorkspaceFileAsync(Project project, Guid projectId)
{
var folders = await ResolveWorkspaceFoldersAsync(project.Path);
var workspaceDocument = new {
folders = folders.Select(path => new { path }).ToArray(),
};
// Generate workspace file...
}
This allows editing multiple sub-repositories simultaneously in one code-server instance, which is very practical for large mono-repo projects. Multiple repositories in one window—like multiple stories in the same book.
Frontend Integration
The HagiCode frontend uses React + TypeScript, and integrating code-server is quite straightforward.
Quick Action Buttons
Add a Code Server button to the project card:
// QuickActionsZone.tsx
<Button
size="sm"
variant="default"
onClick={() => onAction({ type: 'open-code-server' })}
>
<Globe className="h-3 w-3 mr-1" />
<span className="text-xs">{t('project.openCodeServer')}</span>
</Button>
This button triggers the open action and calls the backend API to get the launch URL. One button, one action—simple and direct.
Handling Open Action
const handleAction = async (action: ProjectAction) => {
if (action.type === 'open-code-server') {
const response = await openProjectInCodeServer(project.id, i18n.language);
window.open(response.launchUrl, '_blank', 'noopener,noreferrer');
}
};
Using window.open to open code-server in a new tab, the noopener,noreferrer parameters ensure security. You can never be too careful with security.
Vault Edit Entry
Add a similar edit button in the Vault list:
const handleEditVault = async (vault: VaultItemDto) => {
const response = await openVaultInCodeServer(vault.id);
window.open(response.launchUrl, '_blank', 'noopener,noreferrer');
};
Projects and Vaults use the same opening method, maintaining interaction consistency. Consistency is as important as functionality itself.
URL Building Logic
The code-server URL format requires some attention:
Folder Mode:
http://{host}:{port}/?folder={path}&tkn={token}&vscode-lang={lang}
Workspace Mode:
http://{host}:{port}/?workspace={workspacePath}&tkn={token}&vscode-lang={lang}
Here tkn is the connection token, automatically generated each time code-server starts to ensure secure access. The vscode-lang parameter controls the editor interface language. Each parameter has its purpose—none can be missing.
Use Cases
Use Case 1: AI-Assisted Code Review
User converses with HagiCode, AI analyzes the project code and identifies potential issues. User clicks "Open in Code Server" button to directly open the editor in the browser, view and fix the problematic files, then return to HagiCode to continue the conversation. The entire process is completed in the browser without switching applications. This feeling, well, it's as smooth as flowing water.
Use Case 2: Vault Learning Material Editing
User creates a Vault for learning an open-source project and wants to add study notes in the docs/ directory. Through code-server, they can directly edit Markdown files in the browser, and after saving, HagiCode can synchronously read the updated note content. This is very useful for building a personal knowledge base. Knowledge accumulates value over time.
Use Case 3: MonoSpecs Multi-repository Development
A MonoSpecs project contains multiple sub-repositories, and code-server automatically creates a multi-folder workspace. Users can simultaneously edit code from multiple repositories in the browser and commit changes to their respective Git repositories after modification. This workflow is especially suitable for scenarios requiring cross-repository changes. Editing multiple repositories together is like handling multiple tasks at once—it requires some skill.
Security Considerations
When implementing code-server integration, security is a key area requiring attention. After all, with security, it's too late once problems occur.
Connection Token
The connection-token is randomly generated and should not be leaked. It's recommended to use in an HTTPS environment to prevent the token from being intercepted by a man-in-the-middle. Sensitive information should be protected.
File Path Security
The backend implements path traversal checks:
private static string ResolveLaunchDirectory(VaultRegistryEntry vault, string? relativePath)
{
var vaultRoot = EnsureTrailingSeparator(Path.GetFullPath(vault.PhysicalPath));
var combinedPath = Path.GetFullPath(Path.Combine(vaultRoot, relativePath ?? "."));
if (!combinedPath.StartsWith(vaultRoot, StringComparison.OrdinalIgnoreCase))
{
throw new BusinessException(VaultRelativePathTraversalCode, "Relative path traversal detected.");
}
return combinedPath;
}
This code ensures users cannot access files outside the vault directory through ../ or similar methods. Boundary checks are better done than not.
Permission Control
The code-server process runs with appropriate user permissions to avoid accessing system-sensitive files. It's recommended to use a dedicated user to run the code-server service. Permission control should be in place where needed.
Performance Optimization
code-server consumes server resources. Here are some optimization recommendations:
- Monitor CPU/memory usage, adjust resource limits when necessary
- Large projects may require increased timeout settings
- Implement session timeout auto-cleanup to release resources
- Consider using caching to reduce redundant computation
HagiCode provides a runtime status monitoring API, and the frontend can get current status through getVsCodeServerSettings():
const { settings, runtime } = await getVsCodeServerSettings();
// runtime.status: 'disabled' | 'stopped' | 'starting' | 'running' | 'unhealthy'
// runtime.baseUrl: "http://localhost:8080"
// runtime.processId: 12345
This design allows users to clearly understand the health status of code-server and quickly locate issues when they arise. When status is visible, you have peace of mind.
User Experience Details
During implementation, we discovered some details that affect user experience and deserve special attention:
Opening code-server for the first time may require waiting for startup, which can range from a few seconds to half a minute. It's recommended to display a loading state in the frontend so users know the system is processing. With waiting, feedback is what matters.
Browsers may block pop-ups, requiring users to manually allow them. HagiCode displays guidance information when first opened, telling users how to set browser permissions. User experience is reflected in these details.
It's recommended to display runtime status (starting/running/error), so users can know whether it's a server issue or their own operation when encountering problems. Knowing where the problem lies at least gives you some certainty.
Configuration Example
code-server configuration is straightforward:
{
"vscodeServer": {
"enabled": true,
"host": "0.0.0.0",
"port": 8080,
"language": "follow"
}
}
enabled controls the feature toggle, host and port specify the listening address, and language sets the language mode. These configurations can be modified through the UI interface and take effect in real-time. Simple things are often the most useful.
Summary
HagiCode's VSCode Web integration provides an elegant solution: seamless connection between AI assistant and code editing experience. By integrating code-server in the browser, users can quickly respond to AI analysis results and complete the full workflow from analysis to editing in the same browser session.
Several key advantages of this solution: first, unified experience—projects and Vaults use the same opening method; second, multi-repository support—MonoSpecs projects automatically create workspaces; third, secure and controllable—runtime status monitoring and path security checks.
The solution shared in this article is summarized from HagiCode's actual development. If you find this solution valuable, it shows our engineering practice is solid—then HagiCode itself is worth paying attention to. After all, good things deserve to be seen by more people.
References
- HagiCode GitHub: github.com/HagiCode-org/site
- HagiCode Official Site: hagicode.com
- code-server Official Site: coder.com/code-server
- Related code files:
repos/web/src/services/vscodeServerService.tsrepos/hagicode-core/src/PCode.Application/Services/VaultAppService.csrepos/hagicode-core/src/PCode.Application/ProjectAppService.VsCodeServer.cs
If this article helped you:
- Give us a Star on GitHub: github.com/HagiCode-org/site
- Visit the official site to learn more: hagicode.com
- Watch the 30-minute practical demo: www.bilibili.com/video/BV1pirZBuEzq/
- One-click installation to experience: docs.hagicode.com/installation/docker-compose
- Desktop quick installation: hagicode.com/desktop/
- Public beta has started, welcome to install and experience
Original Article & License
Thanks for reading. If this article helped, consider liking, bookmarking, or sharing it.
This article was created with AI assistance and reviewed by the author before publication.
- Author: newbe36524
- Original URL: https://docs.hagicode.com/go?platform=devto&target=%2Fblog%2F2026-04-12-vscode-web-integration-browser-editing%2F
- License: Unless otherwise stated, this article is licensed under CC BY-NC-SA. Please retain attribution when sharing.
Top comments (0)