Codync
무료 오픈소스 1:1 대안, Grok Bot과 Muse 대신
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Fa is a programming language designed for both AI agents and humans.
Agents get a language they can't get wrong without the compiler noticing: strict types, typed errors, requirements and mutations, clear diagnostics and an unambiguous grammar. Humans get code that reads almost like natural language, and that runs everywhere: web, server, native, WebAssembly.
Syntax-wise, Fa sits between Rust and TypeScript.
-- Load the score of the current user.
function loadScore = (): Integer throws ApiError requires session: Session => {
let response = try fetchScore(session.user.id)
response.score
}
Fa is in active development. Expect breaking changes.
Like Rust, Fa has no escape hatch: no any, no unchecked casts, no null surprises. If it compiles, it works.
An agent can rely on the compiler as its feedback loop instead of on runtime testing.
Fa brings the ideas of the Effect TypeScript library directly into the language, with no wrappers, generators or pipes to learn. Every function signature tells you everything it can do:
throws): there are no exceptions. Errors are values declared in the signature, and the compiler makes sure each one is either propagated with try or handled with catch.requires): dependencies are passed implicitly through the call stack, but they are part of the signature. Calling a function without providing what it requires is a compile error.mutates, invalidates): a function declares what it modifies, down to a field or an element, and which references it can invalidate.type ApiError = Errors {
NetworkError = { message: String }
TimeoutError = { duration: Integer }
}
type Session = {
user: { id: String, name: String }
}
function greet = () requires session: Session => {
console.log("Hello, {session.user.name}!")
}
function main = () throws ApiError => {
provide Session = { user = { id = "42", name = "Ada" } }
greet() -- the session is provided implicitly
-- `try` propagates the error if the call fails
let score = try loadScore()
-- `catch` handles it
let scoreOrZero = loadScore() catch error => 0
}
Diagnostics explain what went wrong, where, and how to fix it. They are written to be acted upon by a human or an agent without guesswork.
Every construct has a single meaning and, as much as possible, a single way to be written. There are few keywords, no context-dependent parsing and no hidden rules, which makes Fa easy to read and easy to generate.
Documentation is part of the language, not a convention on top of it. A comment written right above a declaration is its documentation: it is attached to the declaration and are available to the compiler, the language server and the tooling, so agents always find the documentation right next to the code they work on.
Fa favors words and simple operators over symbols. Code should read almost like a sentence:
for person in persons {
if person.age is 18 {
console.log("Welcome to adulthood, {person.name}!")
}
}
Fa is a universal language: write your code once, then compile it to JavaScript (browser, Bun, Node.js, Deno), native, WebAssembly or Rust source code.
The same code base can power your tooling, your applications and your games.
Fa has no garbage collector and no borrow checker, yet it is 100% memory-safe. It relies on two concepts.
When you reference an element of a collection, its type says where it is stored. The compiler tracks the operations that can move or remove elements, as precisely as it can: after one of them, the references it may have broken must be declared again before being used.
mutable persons: Array(Person) = [{ name = "Ana" }, { name = "Bao" }, { name = "Cleo" }]
use someone = persons[1] -- type: `Person in persons`
someone.name = "John" -- fine: modifying an element keeps the references valid
persons.pop() -- fine: `pop` only invalidates the last element
persons.push({ name = "Dan" }) -- `push` may reallocate the array: every reference into `persons` is invalidated
console.log(someone.name) -- error: `someone` was invalidated by `persons.push`: declare it again with `use someone = persons[...]`
A field that references another object names the collection it lives in, and is one side of a relation whose other side is declared too. The compiler keeps both sides in sync, and deleting an object cleans up every relation it was part of, so no reference is ever left dangling.
mutable people: Bag(Person) = []
type Person = {
name: String
bestFriend: (Person in people)?
bestFriendOf: Bag(people->bestFriend) -- the people whose `bestFriend` is me
}
use ana = people.add({ name = "Ana" })
use bao = people.add({ name = "Bao" })
ana.bestFriend = bao -- `bao.bestFriendOf` is updated automatically
people.delete(bao) -- `ana.bestFriend` becomes `none`
The full documentation lives in documentation/ and is published by the website in packages/website.
To test Fa locally, you need Rust installed. Install it with rustup from https://rustup.rs.
The parser project lives in packages/parser and builds as the fa-parser crate.
From the repository root:
cargo build -p fa-parser
The parser binary expects a file path and prints the parsed tree.
cargo run -p fa-parser -- path/to/file.fa
console.log("Hello, world")